lua-users home
lua-l archive

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


Peter Shook escribió:

> Okay, good point.  But I'm sure Jean Claude has translated this example
> to C and used either lua_rawget or lua_gettable, in which case there
> isn't much difference.

There is, though, there is. It's very important to get this right.
(Thanks, by the way.)

Consider the following expanded example, which allows you to create
objects from templates where the template fields are unmodifiable.
This is a simplified part of a more complex system. This is really
more prototyping than object inheritance, but that's a side-issue.

Here are two implementations, differing only in the line marked
with a star. I've thrown in a bit of functionality to make the
syntax work more nicely, because it's always worth showing how to
do this. But there is lots left out.

We'll start with the rawget implementation.

Lua 5.0  Copyright (C) 1994-2003 Tecgraf, PUC-Rio
> function based_on(template)
>>   return function(init)
>>     return setmetatable(init, {
>>       __index = template,
>>       __newindex = function(t, k, v)
>>                      if rawget(template, k) == nil then  -- *
>>                        rawset(t, k, v)
>>                       else
>>                        error(k.." is read-only for "..tostring(t))
>>                      end
>>                    end,
>>       __tostring = function(t)
>>                      return "<Person "..t.name..">"
>>                    end
>>     })
>>   end
>> end
>
> person = {name = "anonymous", can_edit = false, can_discuss = false}
> member = based_on(person) {can_edit = true, can_discuss = true}
> visitor = based_on(person) {}
> friend = based_on(visitor) {can_discuss = true}
> bob = based_on(friend){name = "bob"}
> carol = based_on(visitor){name = "carol"}
>
> -- On one level, this works fine
> =bob.can_discuss
true
> bob.can_discuss = false
stdin:9: can_discuss is read-only for <Person bob>
stack traceback:
        [C]: in function `error'
        stdin:9: in function <stdin:5>
        stdin:1: in main chunk
        [C]: ?
> =bob.can_discuss
true
>
> -- But at the level below that, we have an oops
> =carol.can_discuss
false
> carol.can_discuss = true
> =carol.can_discuss
true
>
> -- This is where it is both better *and* faster to use
> -- template[k] instead of rawget(template, k)
>
> -- We'll try it again, with template[k]
>
> function based_on(template)
>>   return function(init)
>>     return setmetatable(init, {
>>       __index = template,
>>       __newindex = function(t, k, v)
>>                      if template[k] == nil then  -- *
>>                        rawset(t, k, v)
>>                       else
>>                        error(k.." is read-only for "..tostring(t))
>>                      end
>>                    end,
>>       __tostring = function(t)
>>                      return "<Person "..t.name..">"
>>                    end
>>     })
>>   end
>> end
>
> person = {name = "anonymous", can_edit = false, can_discuss = false}
> member = based_on(person) {can_edit = true, can_discuss = true}
> visitor = based_on(person) {}
> friend = based_on(visitor) {can_discuss = true}
> bob = based_on(friend){name = "bob"}
> carol = based_on(visitor){name = "carol"}
>
> -- Now it works
>
> =bob.can_discuss
true
> bob.can_discuss = false
stdin:9: can_discuss is read-only for <Person bob>
stack traceback:
        [C]: in function `error'
        stdin:9: in function <stdin:5>
        stdin:1: in main chunk
        [C]: ?
> =bob.can_discuss
true
> =carol.can_discuss
false
> carol.can_discuss = true
stdin:9: can_discuss is read-only for <Person carol>
stack traceback:
        [C]: in function `error'
        stdin:9: in function <stdin:5>
        stdin:1: in main chunk
        [C]: ?
> =carol.can_discuss
false
>