lua-users home
lua-l archive

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


John Belmonte wrote:
> Finally, I have a few opinions on upvalues.  The "anti-global"
> programmers out there may not like having to prefix all references to
> the outer scope with % since that will be their most common usage, but
> in practice I haven't found this to be much of a bother.

Yeah, I'm one of them.  And Lua is a little bit unhandy in that field.
It's not that the % is too much to write, it make a special case from
something that should be common - or better say - would be nice if it
were regular stuff.


> However, not being able to modify upvalues is quite painful in terms
> of the effect on my code.  It is especially frustrating since
> functional programming is encouraged by the existence of foreach(),
> etc.  For example take this segment from the function overloading
> program I posted yesterday:
> 
>   function get_typestring( list )
>     local closure = { typestring = "" }
>     local f = function( index, value )
>       local typename = type(value)
>       if (typename == "nil") then typename = "0" end
>       %closure.typestring = %closure.typestring..strsub(typename,1,1)
>     end
>     foreachi( list, f )
>     return closure.typestring
>   end
> 
> If upvalues could be modified it would become:
> 
>   function get_typestring( list )
>     local typestring = ""
>     local f = function( index, value )
>       local typename = type(value)
>       if (typename == "nil") then typename = "0" end
>       %typestring = %typestring..strsub(typename,1,1)
>     end
>     foreachi( list, f )
>     return typestring
>   end

That's not what the patch did.  It would not modify the outer local
but the copy made during the execution of the function definition.
It's a kind of (speaking in C terms) "static local" for each instance
of the function.  And it is only visible within the function itself!
It's useful to keep state from one invocation of a function to its
next invocation.  But the value is not visible from the outside.

To let your example work as intended, you need shared activation
records (probably garbage collected) and that would cost a lot of
performance.  The 1. code fragment simulates this (see the name
"closure" *g*) on a case by case basis.  This table is the shared
part.

The patch resulted from a different kind of view than that of the
designers.  I thought of upvalues as a method to access outer vars.
But they were meant (I think *g*) as a method to pass constants
from the defining scope to the defined scope.  As constants upvalues
are OK.  As a method to access outer scopes - no.  For that you want
stronger methods that are not so limiting.  My patch only scratches
the problems and may make them more confusing.

Here I some things I would like to find a cleaner solution for:

1) local f = function(...) ... %f ... end

   The %f refers to some strange f but not that you meant (the function
   itself).  That's because the "local f" is made visible after the
   expression was evaluated.

2) local f  function f(...)  ... %f ... end

   That one looks better on first sight, but %f is always nil.
   Problem here is a (not obvious) forward reference.
   "local f  f=function(...) ... %f ... end" makes it more
   obvious.  The %f is initialized during evalutation of the
   rhs but the assignement has not taken place yet.

3) local x  function y(...) ... %x=%x+1 ... end

   That is, save state across multiply function calls (static vars).
   Not allowed by Lua.

4) local x  function y(...) ... %x=42 ... end

   With semantic of modify upper scope.

5) local x do local y function z(...)  ... %x ... %y ... end end

   That is, allow access to all upper scopes.

This can all by done with local tables that are passed as upvalues
(see example above).  But this gives not really readable code (simple
things look complicated *g*) and involves a late binding (lookup at
runtime).

It's pretty hard to find clean solutions for these things if a
simple table and the current upvalue mechanism suffices.  Maybe
I just have to get used to this method.  But I'm still trying... ;)

Ciao, ET.