lua-users home
lua-l archive

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

On 2018 Jul 05, at 13:59, Rena <> wrote:

On Thu, Jul 5, 2018, 14:01 Luiz Henrique de Figueiredo, <> wrote:
> One could imagine a mechanism where tables get locked - new keys are not allowed to be added to locked tables, but existing keys could be used in the usual way[

Just set a __newindex metamethod for _ENV that raises an error.

+1. IMO Lua's scoping works great as it is. You don't need to do anything awkward to access globals like `print`, you can have multiple scopes with `_ENV`, and you can attach metamethods to those scopes (including the global one) to do clever things like warn/error on unexpected use of variables. You even can write `_G.x` if you want (or need) to clarify that you're accessing globals, and it's the same syntax as any other table access.

Lua's everything-is-a-table design is excellent, and I think people often don't recognize how powerful it is in its simplicity.

I have to agree with Rena here.  The simplicity of Lua's table structure is very flexible.

Some other thoughts:

At one point, I made my own strict library.  It added a meta-table to _G that would cause an error to be thrown undefined variable was written or read.  So, now I had to explicitly mark a variable as global like this:

__global(“variablename”, value) — essentially the same as _G.variablename = value
__global(“variablename”) — essentially the same as _G.variablename = nil

The second version was still required to even read a nil value.

However, once the variable existed as a global, you could read and write to it as much as you wanted.  It caught the typos, but I really did not like the fact that I had to put the variable names in quotes and thus break standard syntax.  So I stopped that.

What I ended up doing was checking for globals in my unit tests.  My unit testing structure allows me to define a table that is passed into _ENV when the target file is tested.  This table will have any globals I want to use in it, and it will be made strict such that no new globals made be read from or written to it.  If I use an unexpected global during a unit test of that file, the test will fail.  If I list a global to be used in the tests, and it is not used, the I will be informed of its non-use after the file  is done being tested.

What this gives to me:
1) I have an list of all globals that are used.
2) I can use that list to localize all of the globals the file uses at the top of the file, and thus localize them
local pairs = pairs
local print = print

This latter feature has been one I have found particularly useful.  The minor reason is that all globals are localized, and thus make the code more efficient.  The major advantage is that since all the globals are localized, I don’t have to worry about another library doing something silly like redefining how pairs and ipairs work.  This compartmentalizes the code quite nicely, and thus makes it much more reliable.

I anyone is interested, I can share some sample code.