Some enhancement requests

classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

Some enhancement requests

Edgar Toernig
Hi,

while working with lua I made numerous modifications to the source.
IMHO, some of them should be in the standard version.

1. Allow the $if/$ifnot statement to test if debugging is turned on
   so that one can add additional debugging code in lua programs.
   Example:

$if $debug
    print("x.n=", getn(x))
    foreach(x, function(i,v) assert(type(i)=="number", "bad x") end)
$end

   Here's a patch that implements this:   

--- llex.c    Thu Jun 17 19:04:03 1999
+++ llex.c    Thu Mar 23 19:32:50 2000
@@ -117,8 +117,9 @@
 
 
 static int checkcond (LexState *LS, char *buff) {
-  static char *opts[] = {"nil", "1", NULL};
+  static char *opts[] = {"nil", "1", "$debug", NULL};
   int i = luaL_findstring(buff, opts);
+  if (i == 2) return L->debug;
   if (i >= 0) return i;
   else if (isalpha((unsigned char)buff[0]) || buff[0] == '_')
     return luaS_globaldefined(buff);
@@ -132,7 +133,7 @@
 static void readname (LexState *LS, char *buff) {
   int i = 0;
   skipspace(LS);
-  while (isalnum(LS->current) || LS->current == '_') {
+  while (isalnum(LS->current) || LS->current == '_' || LS->current == '$') {
     if (i >= PRAGMASIZE) {
       buff[PRAGMASIZE] = 0;
       luaX_syntaxerror(LS, "pragma too long", buff);



2. The second argument to the next() function should be optional so that
   next(foo, nil) is the same as next(foo).  I use next() regularly to test
   if a table is empty (if next(tab) then print"not empty" end) and the 
   additional nil is disturbing and inconsistent.

--- lbuiltin.c  Sun Apr  2 19:15:41 2000
+++ lbuiltin.c  Sun Apr  2 19:51:54 2000
@@ -320,15 +320,15 @@
 
 static void luaB_next (void) {
   Hash *a = gethash(1);
-  TObject *k = luaA_Address(luaL_nonnullarg(2));
-  int i = (ttype(k) == LUA_T_NIL) ? 0 : luaH_pos(a, k)+1;
+  TObject *k = luaA_Address(lua_getparam(2));
+  int i = (k == 0 || ttype(k) == LUA_T_NIL) ? 0 : luaH_pos(a, k)+1;
   if (luaA_next(a, i) == 0)
     lua_pushnil();
 }

[Side note]
   In my opinion there's an unnecessary difference between handling
   of arguments to C functions and lua functions.  A lua function
   f(a,b) cannot say if it was called via f(a,nil) or f(a).  A C
   function gets either a nil or LUA_NOOBJECT for b.  Why this
   difference?  Isn't nil supposed to stand for "no object"?  ;-)

   I think it would have been better to return nil for not passed
   arguments.  The functions that check for optional arguments
   check against nil instead of LUA_NOOBJECT (then giving exactly the
   same behavior as lua functions).  And an additional function (i.e
   lua_narg()) gives the real number of passed arguments to simulate
   vararg lua functions.

   But I guess it's too late now...



3. The last thing is a little bit more difficult.  A garbage collected
   system is a nice thing to have.  You don't have to care about freeing
   objects.  But often you come to the situation that you want to create
   a new one and assume that it is already present somewhere.  For example,
   you have a function to load a graphics image.  It gets a file name,
   load's it and returns an image object.  The object itself is garbage
   collected.  Now, you want to cache all images, so that you don't have
   to load the same image multiple times.  But unfortunately, the cache
   itself holds a reference to every image and it is no longer garbage
   collected :-(

   What you want: weak references that won't hinder the gc of collecting
   the referenced object.

   My first idea was:  add a function to mark a table as holding weak
   reference which means, all values (not indexes) hold in that table
   will not be marked during the mark phase.  Later in the collection
   phase replace all table values not marked with nil.  But the imple-
   mentation is not that easy and I'm still not sure if this really
   works.  (I would love to hear comments about this idea, especially
   if this would really work.)

   So I went an easier way.  The C-API already has a method to hold weak
   references (lua_ref(0)).  I just created some bindings to access them
   from lua.  Because the references itself have to be garbage collected
   I mapped them to userdata with a private tag.  The result:  there are
   two new functions, x = ref(obj) and  obj = getref(x).  getref returns
   nil if the object referenced by x is already garbage collected.

   I think, these two function are elementary enough to be part of the
   standard list of builtin functions (the short names may be a problem).

   Here is a code fragment of my implementation:

lua_api
xlua_ref(void)
{
    lua_pushobject(luaL_nonnullarg(1));
    lua_pushusertag((void*)lua_ref(0), tag_ref);
}

lua_api
xlua_getref(void)
{
    lua_Object o = lua_getparam(1);

    luaL_arg_check(lua_tag(o) == tag_ref, 1, "reference expected");
    o = lua_getref((int)lua_getuserdata(o));
    if (o != LUA_NOOBJECT) /* object not already gc'ed */
        lua_pushobject(o);
}

static void
gc_ref(void)
{
    lua_unref((int)lua_getuserdata(lua_getparam(1)));
}



Ok, that's all for the moment.  Discussion opened *g*

Ciao, ET.


Reply | Threaded
Open this post in threaded view
|

Re: Some enhancement requests

Luiz Henrique de Figueiredo
>From: Edgar Toernig <[hidden email]>

>1. Allow the $if/$ifnot statement to test if debugging is turned on
>   so that one can add additional debugging code in lua programs.

The purpose of $debug is to enable better error messages, not to support
user-level debugging.
I think you could do what you want using a global variable, say DEBUG,
and then write:

$if DEBUG
    print("x.n=", getn(x))
    foreach(x, function(i,v) assert(type(i)=="number", "bad x") end)
$end

To enable this code using the standard standalone interpreter, you can simply
do	lua DEBUG=1 myfile.lua

>2. The second argument to the next() function should be optional so that
>   next(foo, nil) is the same as next(foo).  I use next() regularly to test
>   if a table is empty (if next(tab) then print"not empty" end) and the 
>   additional nil is disturbing and inconsistent.

Using "next" to test whether a table is empty is a clever idea, but it got me
thinking *why* you would want to do this.

Anyway, the request sounds reasonable to me. We'll see...
--lhf

Reply | Threaded
Open this post in threaded view
|

Re: Some enhancement requests

Alan Watson-2
>2. The second argument to the next() function should be optional so that
>   next(foo, nil) is the same as next(foo).  I use next() regularly to test
>   if a table is empty (if next(tab) then print"not empty" end) and the 
>   additional nil is disturbing and inconsistent.

Surely it would be better to use a wrapper function:

  function isempty(t) 
    return not next(t, nil) 
  end

Regards,

Alan
-- 
Dr Alan Watson
Instituto de Astronomía UNAM

Reply | Threaded
Open this post in threaded view
|

Re: Some enhancement requests

Edgar Toernig
Alan Watson wrote:
> Edgar Toernig wrote:
> >2. The second argument to the next() function should be optional so that
> >   next(foo, nil) is the same as next(foo).  I use next() regularly to test
> >   if a table is empty (if next(tab) then print"not empty" end) and the
> >   additional nil is disturbing and inconsistent.
> 
> Surely it would be better to use a wrapper function:
> 
>   function isempty(t)
>     return not next(t, nil)
>   end

What I wanted was a next function that is compatible to the standard lua
calling conventions.  In code:

    function next(a,b) return %next(a,b) end

Ciao, ET.

Reply | Threaded
Open this post in threaded view
|

Re: Some enhancement requests

Edgar Toernig
In reply to this post by Luiz Henrique de Figueiredo
Luiz Henrique de Figueiredo wrote:
>
> Using "next" to test whether a table is empty is a clever idea, but it got me
> thinking *why* you would want to do this.

Why I want to test whether a table is empty?!?  Because I want to see if it
contains some elements. *verypuzzled*g*

Ciao, ET.

Reply | Threaded
Open this post in threaded view
|

Re: Some enhancement requests

Luiz Henrique de Figueiredo
In reply to this post by Luiz Henrique de Figueiredo
>From: Edgar Toernig <[hidden email]>
>
>Why I want to test whether a table is empty?!?  Because I want to see if it
>contains some elements. *verypuzzled*g*

Of course.
I meant only that I did not seem to be a "natural" thing to do in Lua.
I'd say that the "natural" thing to do with tables is to use "foreach", or a
loop of "next", in which nothing gets done if the table is empty.
But your mileage may vary...
--lhf