lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


It was thus said that the Great Soni L. once stated:
> 
> > On 30/09/15 12:56 PM, Sean Conner wrote:
> >It was thus said that the Great Soni L. once stated:
> >>In Lua you have 2 options:
> >>
> >>1) Use function upvalues. (for local access)
> >>
> >>2) Use the module table. (for shared access)
> >>
> >>There's no such thing as a "registry" in Lua, it only exists in C (and
> >>debug). I want to bring Lua on par with the C API and vice-versa.
> >   I think I may have mentioned this before, but wrap Lua in Lua.
> >
> >	lua = require "lua"
> >
> >	L = lua.Lnewstate()
> >	L:Lopenlibs()
> >	
> >	L:getglobal("print")
> >	L:push("this is a string")
> >	L:call(1,0)
> >
> >   Short of that, what's in the C API that isn't available from Lua?
> >
> >   -spc (debug.getregistry() called.  It's a bit miffed)
> >
> Well there are no functions to manipulate varargs as in
> 
> insert(pos, newarg, ...) -> return ...[1,pos], arg, ...[pos+1,-1]
> remove(pos, ...) -> return ...[1,pos-1], ...[pos+1,-1]
> replace(pos, arg, ...) -> return ...[1,pos-1], arg, ...[pos+1,-1]
> sort([f ,]...) -> return sorted ...
> reverse(...) -> return reversed ...
> slice(i, j, ...) -> return ...[i, j]
> etc

  Okay, fair enough.  
  
> Either way, the original suggestion is/was to REMOVE the registry, not 
> to make it available from Lua. If Lua doesn't need a registry then 
> neither does C.

  One use of the registry for C is to register metatables for userdata.  For
instance, the io module registers "FILE*" in the registry to reference the
metatable for open files.  This has two uses---one, it's a reference to a
single metatable for all open files and two, it allows some typechecking in
the C code:

	FILE **pfp = luaL_checkudata(L,1,FILEHANDLE);

  If the datum at index 1 is not a userdata who's metatable is not the same
as "FILE*" in the registry, then Lua will throw an error.  Yes, you could
do:

	FILE **pfp = lua_touserdata(L,1);

and hope for the best, but any errors might not be caught properly and the
user will end up with a crashed interpreter/program.  In Lua, a table
without the proper metatable will result in a catchable (pcall()) error, not
a crash.  It's a different outcome.

  Now, let's assume that the registry doesn't exist (it's easy if you
try)---just write Lua modules in C without using any Lua function that uses
the registry (like luaL_newmetatable() or luaL_getmetatable()).  You could
attempt to get by with using lua_touserdata() and hope for the best, but I
think you would reject that (I know I wouldn't be happy with that).  One
method might be to include a __type field in the metatable with a checkable
value:

	luaL_getmetafield(L,-1,"__type");
	if (lua_isnil(L,-1))
	  lua_error(L...);
	type = luaL_checkstring(L,-1);
	if (type == NULL)
	  lua_error(L...);
	if (strcmp(type,"FILE*") != 0)
	  lua_error(L...);
	pfp = lua_touserdata(L,1);

  Of course, that could be wrapped up in a function like
luaL_checkmetatype() or something, but the thing is, okay, that could work. 
But there's still an issue---where do you store a reference to the
metatable, for when you do:

	FILE **pfp = lua_newuserdata(L,sizeof(FILE *));
	/* ... um ... where's the metatable? */

  Global namespace?  Bad for several reasons.  Upvalues?  Okay, io.open()
would need an upvalue to store the metatable.  io.popen() as well.  Quite
possibly io.lines() (haven't checked the implementation) and definitely
io.tmpfile().  The Lua API doesn't have a way to register a mass number of
functions of which only a sub-set have upvalues.  All, yes?  Some ... not so
much.  You could give all functions under io an upvalue, but some might
consider that a waste of space.

  But okay, we can extend the API to luaL_setfuncs() and luaL_Reg to get
around this (extend the structure and function, or a new structure and
function, or whatever ...).  The above can be coded as:

	FILE **pfp = lua_newuserdata(L,sizeof(FILE *));
	lua_pushvalue(L,lua_upvalueindex(L,1));
	lua_setmetatable(L,-2);

  So we're almost homefree.  One last use of the registry.  In my own syslog
module [1], I save the ident string passed to org.conman.syslog.open() in
the registry.  I do this because openlog() just saves the pointer to the
string passed in (it several implementations---I found this out the hard
way) so I need to keep the string pinned.  I need *somewhere* to stash the
string.  Again, I could create an upvalue to store this, but it's just this
one function.  In another (unpublished) module wrapping Xlib, I store the
current display in the registry.  Again, I could stash this in an upvalue,
but there are more functions that require this (but not all!).  Again, the
new API to give some functions an upvalue could help here.

  It's doable, but I think it gets ugly rather fast, but this is purely
speculation on my part.  Have you tried writing a C module without using the
registry (or any functions that use the registry)?

  -spc

[1]	https://github.com/spc476/lua-conmanorg/blob/master/src/syslog.c