lua-users home
lua-l archive

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


On Aug 5, 2005, at 2:37:53, Mike Pall wrote:
The reason is that 'local by default' does not mix well with
lexical scoping. The languages that use this either do not
have proper lexical scoping (and thus don't have the problem)
or need some ugly workarounds. It's a common language design
mistake (IMHO).

From what Google tells me, lexical scoping is the same as "static scoping". This confuses me a little, because static scoping is what C and other languages use (or is that where "proper" comes in?). Is the scope operator in C++ (::) what you'd call an "ugly workaround"? Could you perhaps elaborate what exactly you mean? While I've written my share of parsers, lexers and bytecode compilers, I'm all self- taught, and thus occasionally don't know the proper technical terms... I tried to look it up in Wikipedia, but the article there redirects to "scope", and doesn't at all clarify which of the described concepts is "lexical scope".

Proper lexical scoping really requires that you have a choice
between mutating a binding (assignment) and creating a new
binding (declaration). Alas, the 'local by default' rule mixes
them and makes an assignment do both. Consequently you cannot
modify a variable in an outer scope with a simple assignment
(because that would create a new local variable with the same
name).

Unless of course you introduce an extra declaration to make up
for this. E.g. in Python this is the 'global' statement. But
this only allows you access to the outermost scope (module level).
This has little to do with proper lexical scoping.

Yeah, that's what HyperTalk did as well. On the other hand, what C does is just use a global variable if it's present, unless you declared a local variable of the same name in the current scope. I'm a little confused why this can't be done in Lua, or why that wouldn't be desirable. But I'm willing to learn.

The only real workaround in Python is to create a mutable
container (a list) in the outer scope. But then you have to use
list access and list assignment everywhere (x[1] = x[1] + 1).
Yuck. That's why closures in Python are ... uh ... unpopular.

 Yeah, that would be ugly.

 So far I thought it was safer if variables are local by default, so
code can't accidentally change another object's variables (e.g.
during a recursive call).

You can add metamethods to the globals table to catch undefined
reads/writes and print a warning or stop with an error. Lua 5.1
has a command line option '-w' that does this for undefined reads.

So, you're saying I could use a metamethod to actually turn off automatic declaration of globals? That would be a way around it, I guess.

Though right now, I'm still trying to find out whether I really don't want automatic globals. The thing is this: The project for which I'm investigating the use of Lua is aimed at beginning programmers. As such, I'd need the language to not allow too many casual bugs. One of the bugs I first thought of when looking at Lua would be if the user forgot to add the "local" keyword inside one of their functions. In that case, they'd get a global, and the code would compile just fine, until they call another function that uses a global of same name. Bugs like that would be hellishly hard for a newbie to figure out.

Am I worrying too much? Can anyone give me a rationale why this won't be that much of a problem? Automatic global creation comes in handy when declaring new objects, because

foo = {}

automatically makes foo end up in global scope, just as a 'class' declaration would.

BTW: Two weeks ago I found something related (well, a bit):

       http://opal.cabochon.com/~stevey/sokoban/

This is an interesting comparison of dynamic languages for the
Java VM (Jython, Groovy, NetRexx, ...). The author wrote the
same program (Sokoban) in different languages and discusses the
pros and cons of each language (language design, not benchmarks).
He talks about the above problem, too.

I guess you're referring to the mentions of scope in the PNuts chapter? Lua's way of always being global IMHO has the same problem, just the other way round. While PHP and all similarly-scoped languages require you to "pull in" global variables, Lua requires you to explicitly deny that you want a global. Considering the majority of variables in most programs seem to be locals, I'd personally take a language I wrote in the direction of PHP and co.: The default would be what's most frequently used. If you notice some code doesn't get its correct value from a global, it's a fairly straightforward to realize you need to pull in a global. OTOH, if writing one function suddenly causes another completely unrelated one to return odd values, it is quite difficult to a) locate the function that's screwing up my global and b) to even get the idea that they might both be using variables with the same names.

The author of these very interesting comparisons seems to have a similar opinion: >> Lexical scoping is lexical scoping -- you should always be able to determine the nested lexical scopes by looking at the code nesting. No exceptions.<<

Which I read as: Top level variables should be global, variables in lower levels (e.g. functions) should be function-local.

However, being a programmer, I know how easy it is to pull in a global variable in a language where assignment may implicitly declare a variable. I might expect to be declaring and initializing a local, while I'm in fact changing a pre-existing global. In light of that, the ideal solution seems to me to either have a special section for globals which will automatically be used by all other scopes (like Pascal), or requiring explicit declaration of both kinds of variables.

Now, note I'm not dictating you change Lua to fit my whims. I'm simply stating what problems I see. I may be overlooking some obvious solutions to these problems.

Cheers,
-- M. Uli Kusterer
http://www.zathras.de