lua-users home
lua-l archive

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

Mark Hamburg writes:
> Consider the following: ...
>     local f = "foo.txt" )
>     unwind_protect( io.close, f )( function()
>         print( f:read( "*a" ) )
>     end )

If you'll need to unwind multiple objects, an approach similar to [1] could be
more flexible:

  try(function(stk, ...)
    local f  ='in.txt'      ); stk:finally(io.close, f)
    local f2 ='out.txt', 'w'); stk:finally(io.close, f2)
    f2:write(f:read '*a')
  end, ...)

Structurally, that is similar to the proposal in [2] but with the semantics of

    local f  ='in.txt'      ); finally io.close(f)  end
    local f2 ='out.txt', 'w'); finally io.close(f2) end
    f2:write(f:read '*a')

> On the other hand, it behaves unexpectedly if we write:...
>     unwind_protect( io.close, f ) do
>         return f:read( "*a" )
>     end

True, unless Lua is somehow extended so that a function like "unwind_protect"
could itself trigger a return in its caller (like certain control structures can
do).  We maybe could extend the CALL opcode to conditionally cause a RETURN if
the called function sets some flag.


The major question I have is whether "do" should be syntactic sugar for
"function()".  This "do" syntax has been proposed before and even implemented as
a patch[3].

If so, then it would seem consistent to allow something like this:

  function f() do return g() end end

to be rewritten equivalently as this:

  function f() function() return g() end end

Does that make sense?  "function() return g() end" is normally an expression,
but it's being used here as a statement, and in that context it is getting
evaluated.  (Lua does allow that a function call "g()" be interpreted as either
an expression or a statement though.)

Similarly, then, should these have identical behavior?

  while a do b() end
  while a function b() end

Should we even allow this?

  local h = function() return g() end
  function f() h end

Maybe that goes too far...h evaluates to a function only at run-time.  For
similar reasons we want that

  function g() do         return 2 end; return 3 end  -- returns 2
  function g() function() return 2 end; return 3 end  -- returns 2

  function f() return 2 end
  function g() f(); return 3 end  -- returns 3

Another consideration is that the following two statements are currently
considered equivalent according to the language specification:

  local f = function() return end
  local f = function() end

so then should these two also be equivalent?

  while true do return end
  while true do end

Obviously, not.  To reconcile this, "function() return end" and "function() end"
must be considered as different.

In practice, the two do actually generate different byte codes:

        1       [1]     RETURN          0 1
        2       [1]     RETURN          0 1

        1       [1]     RETURN          0 1

That currently isn't defined behavior, but maybe it is a convenient one that
could be used as the above mentioned differentiating "flag" permitting

  function f() try(do return 2 end) return 3 end
  assert(f() == 2)  -- Yes, the "try" function can somehow forward
                    -- the "return 2" under the "CALL opcode"
                    -- extension noted above.

So, do we really want "do" to be syntactic sugar for "function()"?


Incidentally, I'm working on a patch that would extend "do ... end" not
necessarily as syntax sugar for closures but rather to allow something like this

  local a = do local b = c*c; if b < 2 then return end end

which would behave like

  local a; do
    local b = c*c
    if b < 2 then return end
    a = b+1

That is, the expression "do <chunk> end <expr>" evaluates to the expression
"<expr>" inside the lexical scope of "<chunk>".  I believe Rici and I had
similar ideas[4] that differed only in surface syntax (e.g. "let <chunk> in
<expr>" rather than "do <chunk> end <expr>").

[3] - "Do patch", Asko Kauppi