lua-users home
lua-l archive

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

Peter Shook escribió:
> local ReadOnly = {
>   x = 5,
>   y = 'bob',
> }
> local function check(tab, name, value)
>    if rawget(ReadOnly, name) then
>      error(name ..' is a read only variable', 2)
>   end
>   rawset(tab, name, value)
> end

> setmetatable(_G, {__index=ReadOnly, __newindex=check})

There is no reason to do rawget(ReadOnly, name) since ReadOnly
has no metatable. (And if it did, it should probably be respected.)
ReadOnly[name] is considerably faster because it requires neither
a lookup in the environment table nor a function call.

Just a little suggestion -- I have noticed the spurious use of
rawget and rawset in a number of pieces of example code, so I
thought I would mention this.

An interesting variant of the above, which is not the solution to
the problem posed but has other uses. There are some obvious improvements,
including using the facility I put into the WeakTablesTutorial on how
to give globals printable names.
(see <>)

function protect(defined)
  -- returns a new table which only allows keys to be set once,
  -- and a proxy table which can be used to override the
  -- restriction, in that order.
  -- This is a debugging tool, not a security tool.
  -- (although you can simply let the override proxy disappear)

  local function ban_reset(t, k, v)
    if defined[k] then
      error(tostring(k).." has already been defined")
      defined[k] = v

  local new_table = setmetatable({}, {
    __index = defined,
    __newindex = ban_reset

  local function allow_reset(t, k, v)
    rawset(new_table, k, v)

  local unprotected_proxy = setmetatable({}, {__newindex = allow_reset})

  return new_table, unprotected_proxy

-- Now, we apply it to the global table.
_G, setq = protect(getfenv(0))

-- Just setting _G is not enough to change the environment
setfenv(0, _G)

-- This is necessary to avoid "error handling error"
-- There ought to be a better way of dealing with this :)

Here's how it works:

> -- Here is how it works:
> =math
table: 00443550
> -- I can't redefine that
> math = nil
stdin:10: math has already been defined
stack traceback:
        [C]: in function `error'
        stdin:10: in function <stdin:8>
        stdin:1: in main chunk
        [C]: ?
> -- Of course, I could redefine a member
> sin = math.sin
> math.sin = function() print "gotcha" end
> =math.sin(3)
> math.sin = sin
> -- Probably I should have recursively protected
> -- tables before I protected the globals
> -- Now, I can create any new global
> function foo(x) return "Hello, "..x end
> =foo "world"
Hello, world
> -- But I can't redefine it
> foo = 7
stdin:10: foo has already been defined
stack traceback:
        [C]: in function `error'
        stdin:10: in function <stdin:8>
        stdin:1: in main chunk
        [C]: ?
> -- If I want to create a redefinable global, I use setq
> -- (Table syntax is used rather than function syntax to avoid typing 
> = 7
> -- Now, the global is unprotected and it doesn't matter if I use
> -- setq or not on it.
> bar = 8
> = 42
> =bar