lua-users home
lua-l archive

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


On Thu, Jul 15, 2010 at 8:40 PM, Edgar Toernig <froese@gmx.de> wrote:
> Roberto Ierusalimschy wrote: [...]
>> - An assignment to a free "a" that is inside the scope of another global
>> declaration is an error ("attempt to assign to undeclared variable 'a'").
>
> Rather bizarre ...

I'm trying to think when I would use this.  Under my normal coding
style, I have no real problem with unintentional global sets
associated with SETGLOBAL opcodes because I ban SETGLOBAL (plus other
things) in my lint checks.  Perhaps the only small improvement to this
would be some standardized way (e.g. pragma or comment) to assert in
source code that "SETGLOBAL opcodes are banned" so that the Lua
compiler can bark on it without the complication of running an
external tool (which newbie users wouldn't do).  My `checkglobals`
function ( http://lua-users.org/wiki/DetectingUndefinedVariables )
kind-of was one way to address that.  The `global CHECK` under this
recent proposal does that too, though as a curious side-effect of
other features.

The interesting question is whether this `global` keyword proposal
would convince me to again allow SETGLOBAL (or the equivalent opcode
in 5.2).  Here's how I think `global` is intended to be used:

  local one = 1
  local two = 2
  local print = print

  f(function(_ENV)
    local counter = 1
    global two
    global function one() two() end
    global function two() one() end
    global function three()
      countar = countr + 1
      print(counterr)
    end
  end)

Observations: You'll notice that the `global` before `function one()`
is necessary since otherwise the local in the enclosing scope will
wrongly make it a local.  This is good: it avoid subtle bugs.  We
will, however, need the forward declare `global two` since otherwise
the call `two()` will wrongly resolve to the local in the enclosing
scope.  So, like `local`, the `global` keyword may sometimes, though
probably more rarely, require a forward declaration.  The `three`
function has `counter` misspelled in three places.  `countr + 1` is
not detected at compile time but at least is detected at runtime as
arithmetic on `nil` if the execution covers `three` (ok).  The
assignment error `countar =` is detected at compile time via the
global checking that is first triggered by the line `global two`.  The
`print(counterr)` error is not detected at all, at least directly.
Finally, the global `print` needs to be accessed within the
environment `_ENV`, which remains a problem because `print` doesn't
belong inside `_ENV`.  That problem may be handled via the various
usual techniques (`__index=_G` hackery, making `print` a local in the
outer scope, or making `_G` a local in the outer scope and doing
`_G.print` inside).

Here's how I normally would instead write that:

  --! noglobalsets()

  local one = 1
  local two = 2

  f(function(M)
    local counter = 1
    function M.one() M.two() end
    function M.two() M.one() end
    function M.three()
      countar = countr + 1
      print(counterr)
    end
  end)

Isn't that simpler?  Moreover, it doesn't have the problem resolving
`print`.  To handle the problem of `print` within the `global`
proposal, I think a proper solution is like what I mentioned in [1].

[1] http://lua-users.org/lists/lua-l/2010-07/msg00262.html