lua-users home
lua-l archive

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


On 25/02/2008, John Hind <john.hind@zen.co.uk> wrote:
> Mark Meijer [meijer78@gmail.com] said:
>  <<
>  I certainly don't hope the _G.myglobal syntax is going to be required.
>  I prefer the explicit forward declaration way. Sure, _G sticks out, and
>  that's because it's ugly. Forward declarations stick out well enough and are
>  much nicer and cleaner, imho.
>
>  Also, I think what you want is to handle initialization differently.
>  Not assignment. And reference (in the sense you meant it) is only harmless
>  if the variable has already been initialized. The forward declaration
>  approach handles this nicely.
>  >>
>
>
> I'm not sure what you mean by "the forward declaration approach": do you
>  mean 'global x' on analogy with 'local x'? If this applies to reference as
>  well as assignment does it mean that you have to explicitly declare
>  everything, even library functions?

What I meant was exactly the way it works with strict.lua, as Roberto
also suggested. It's a bit like you say "global x" as analogous to
"local x", except the "global" keyword isn't even needed. It's not
really a declaration, strictly speaking, but that is how it
conceptually works. This "declaration" and initialization is basically
the same in Lua, although you can just as easily initialize with nil
if you're only "declaring" a global for future use (e.g. for use
inside a function), as follows:

gMyGlobal = nil;

-- or:

gTimeout = 10;

-- or:

function foo(a) return a + 1; end

That's all there is to it. As you can see, you don't need to
separately "declare" functions (nor globals) in advance (which is
called forward declaration), as long as they're initialized before
they're first used, obviously. With strict.lua being a run-time aid,
you can create globals anywhere (i.e. also within a function), it just
prevents you from "referencing" (reading) globals that have not been
created yet, which often happens due to typing errors. If a
compile-time variant of this should be implemented, I'd vote for
taking it one step further by only allowing new globals to be created
from within global scope. This is what I meant by handling
initialization of globals differently, but not assignment (i.e. once a
global is created in global scope, you can use it - read and assign -
from anywhere as normal).



>  When I thought this out originally, I realised that all the compiler can do
>  once it has exhausted a search for a name in its local tables is to compile
>  it blindly as a late bound global (table lookup). It cannot know if the
>  global will exist at runtime and therefore if it will be initializing or
>  assigning. It can however distinguish whether it is programming to reference
>  (read) a global or to assign (write if it exists, create and write if it
>  does not).

True, it would require some additional work by the compiler, for it to
know when a variable being used is an existing global or not. However,
if globals can only be created from within global scope, i.e. top
(chunk) level code, it shouldn't be to difficult to keep a list of
created globals as it encounters them, while compiling. The only
drawback I think is that, with a single-pass compiler, the code which
creates some global should always precede any code which intends to
use that global. On itself, that might not be a big downside, but
since this is currently not the case, it could prevent existing code
from compiling (without rearranging that code or adding the necessary
"forward declarations").



>  In my view, you should not be allowed to assign a value to a global variable
>  without being explicit about it. I have no problem if the syntax is "global
>  x = 1" or "getfenv().x = 1" or "_G.x = 1", although the latter two are more
>  versatile and avoid another reserved word. Also, I see the argument that you
>  do this once in a chunk and then you can implicitly assign it from there on.

Exactly, I think assigning to an already existing global doesn't need
to be a special case, just creating (declaring/initializing) new
globals. Since you would already have to be explicit about the
creation of globals, subsequent assignments to them are generally no
accident, and needs no special syntax. If the strict.lua way is taken,
even creation of new globals needs no special syntax (nor new
keywords), it's just limited to the chunk level and therefore you
can't "implicitly" create a new one from within a function (be it
accidental or not).



>  I do not see why you say "_G.x" is ugly - unless it is the leading
>  underscore which could easily be fixed.

Well, _G.foo is used to explicitly denote global scope (I guess
somewhat similar to "::foo" in C++), but I don't think it's desirable
to make that a requirement for every access to every global. Strictly
speaking, it's even based on an assumption, namely that _G is really
the globals table (even though it might potentially be shadowed by a
local variable called _G, for example). Why I think it's ugly, I don't
know, I can't really put my finger on it. It just seems ugly to me,
like a bit of a hack or... I don't know.



>  I do not get why Roberto wants to limit the forward declarations to the
>  chunk level: if you are going to have them, why not let them work the same
>  as locals, so the declaration has lexical scope? But they have to lock out
>  assignment (write) only, or it will be as bad as "C" with every chunk
>  starting with huge imports of header files!

If I understand you correctly here, then I think I just explained why
limiting global declarations to the chunk level would be a good idea.
:) I'm not sure if I understand the rest of what you say here. How do
you mean to have lexical scoping for globals that are not created on
the chunk level... wouldn't that by definition make them locals? And
you mean to make them only writable from within the same scope (and
deeper) as where they are created, and read-only everywhere else?
Maybe I'm confused, but I don't see how that would be useful.