lua-users home
lua-l archive

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


On Fri, 9 Jul 2010 01:57:06 -0400, David Manura <dm.lua@math2.org> wrote:
> Ok, so when do I think globals are appropriate?  The first and primary
> case is when retrieving variables from the standard library:
>
>  print(math.sqrt(2))
>
> Here's why I think this is acceptable:
>
>  (1) Typos can be statically detected here.

> Typos to
> members and signatures (e.g. "math.sqrrt(2,true)") are not detected in
> the above approach.

Typos in member references can be automatically detected if the
module's exports are known.  I wrote the Darwin module system in part
for this reason.  However, I've not yet implemented the static
analyzer -- I would prefer to use an existing one and simply feed it
the module exports to check against.  In Darwin, _G is just another
module, btw.

>  (2) Optimization is best left to the compiler.

I heartily agree.  Some functional language run-time environments
(like Scheme48) support a form of inlining that should be possible to
do in Lua.  The idea is this:  You declare a list of globals whose
values you will not change.  The compiler is then free to inline the
value of those globals instead of generating lookup code.

>  (3) Localizing every top level function (e.g. print) is cumbersome
> to do manually.  [...]  Lua
> doesn't have a "import static foo.*" like Java [6].

Darwin's import function ('structure.open', which can be melifluously
triggered by Lua's 'require') is function that creates "global"
variables (or tables thereof) through which a module's functions and
objects become accessible.  Since it's an ordinary function, it cannot
create locals.  It would be an interesting project to pre-process Lua
source that uses Darwin modules such that locals are created for the
imports.  As long as the limit on the number of locals in a chunk is
not exceeded, such a code transformation might yield performance gains
in a fully automated fashion.

>  (4) It can work ok if custom environments are implemented carefully
> or avoided.  If the current environment is changed, then the standard
> library functions must remain exposed through the new environment.

This is how Darwin works.   All of the module bindings (including _G,
which is just another module) are stashed away.  When you open a
module, you get a copy of the bindings so your module code can do
whatever it wants.  I didn't use the metatable __index approach
because I wanted Darwin to support (by trivially wrapping) as much
existing Lua code as possible, including code that installs its own
metatable for _G or other environments.

> Now, I think globals get messier when you have custom environments, or
> even multiple environments in the same file

And this is why Darwin modules (and the "main" program) do not share
the same _G.  I guess you could say that when I use Lua (i.e. with
Darwin loaded), globals are not actually global.   Everything in _G,
whether it was there ab initio or whether my code created it, is
visible only to my code.  My "main" code cannot create globals that
are visible to the modules I have loaded, nor can any module create a
global that is visible to other modules or to my "main" code.

In my opinion, this is a very useful (and well-appreciated in the
literature) meaning of "lexical scope" in the context of module
systems.   After all, the definition of lexical scope is that you know
the binding of every reference from only a lexical analysis -- i.e. by
reading the program.  Lua's out-of-the-box module system does not
provide this.  The dynamic environment into which a module is loaded
affects the bindings used inside module code.

Jim