Read-only table

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Read-only table

Ervin Hegedüs
Hi,

sorry for this question, may be it's so trivial... but I got
stuck... I just try to understand what's the difference between
two methods below, where I'ld like to make a read only table.

x = {a = "AA"}

function readonlytable(table)
    return setmetatable({}, {
      __index = table,
      __newindex = function(table, key, value)
                    error("Attempt to add a new or modify an exists item to a read-only table")
                   end,
      __metatable = false
    });
end

setmetatable(x, {
    __index    = x,
    __newindex = function(x, key, value)
                    error("Attempt to add a new or modify an exists item to a read-only table")
                end,
    __metatable = false
});

Now I try:

x.a = "BB"

which is *works* (this isn't expected)

x.b = "bbb"

*doesn't work* (this is expected)

When I do:

x = readonlytable(x)

and then

x.a = "BB"

then I got (the expected) behavior:

lua5.3: ro2.lua:8: Attempt to add a new or modify an exists item to a read-only table
stack traceback:
        [C]: in function 'error'
        ro2.lua:8: in metamethod '__newindex'
        ro2.lua:24: in main chunk
        [C]: in ?


So, why does work the function readonlytable() and why doesn't
the "inline" form of same method?



Thanks,


a.
Reply | Threaded
Open this post in threaded view
|

Re: Read-only table

Robert Burke
> So, why does work the function readonlytable() and why doesn't
> the "inline" form of same method?

They are not the same code. In readonlytable you create a new table
whose metatable's __index points at the passed in table (called
"table"). So there are 3 tables in this story:

a totally empty table, which is returned
that table's metatable
the table in which values are looked up

In the other copy of the code, the first and third tables are the
same, rather than being different. This is bad. You really want to
make sure the first table is totally empty. __newindex and __index are
only called if the key cannot be looked up in the table, so they won't
be called for the entries that are actually in the table.
Reply | Threaded
Open this post in threaded view
|

Re: Read-only table

Ervin Hegedüs
Hi Robert,

first, many thanks for the clarification,

On Tue, Jun 23, 2020 at 07:20:04PM +0900, Robert Burke wrote:

> > So, why does work the function readonlytable() and why doesn't
> > the "inline" form of same method?
>
> They are not the same code. In readonlytable you create a new table
> whose metatable's __index points at the passed in table (called
> "table"). So there are 3 tables in this story:
>
> a totally empty table, which is returned
> that table's metatable
> the table in which values are looked up
>
> In the other copy of the code, the first and third tables are the
> same, rather than being different. This is bad. You really want to
> make sure the first table is totally empty. __newindex and __index are
> only called if the key cannot be looked up in the table, so they won't
> be called for the entries that are actually in the table.

so if I understand correctly I can make a _real_ read-only table
only with the readonlytable() function? And in this case what happens
with the "original" table? There is a point when two tables
exists in same time in memory? When readonlytable() returns, it
freed? It's interesting from the point of memory usage.

Thanks,


a.
Reply | Threaded
Open this post in threaded view
|

Re: Read-only table

Robert Burke
> so if I understand correctly I can make a _real_ read-only table
> only with the readonlytable() function?
No, you could do the same thing with the inline code if it was more
like the code in your function:

x = setmetatable({}, {
    __index    = x,
    __newindex = function(x, key, value)
                    error("Attempt to add a new or modify an exists
item to a read-only table")
                end,
    __metatable = false
});

> And in this case what happens with the "original" table?

It lives on because your table holds a reference to the metatable and
the metatable holds a reference to the old table. But hopefully no
other code can get a reference to it, because then it wouldn't really
be read-only!
Reply | Threaded
Open this post in threaded view
|

Re: Read-only table

Ervin Hegedüs
Hi again,

On Tue, Jun 23, 2020 at 07:44:29PM +0900, Robert Burke wrote:

> > so if I understand correctly I can make a _real_ read-only table
> > only with the readonlytable() function?
> No, you could do the same thing with the inline code if it was more
> like the code in your function:
>
> x = setmetatable({}, {
>     __index    = x,
>     __newindex = function(x, key, value)
>                     error("Attempt to add a new or modify an exists
> item to a read-only table")
>                 end,
>     __metatable = false
> });

ah, thanks - it works as well.

Now I have to figure out how can I use it through C-API.

If you have any idea, please let me know :)

> > And in this case what happens with the "original" table?
>
> It lives on because your table holds a reference to the metatable and
> the metatable holds a reference to the old table. But hopefully no
> other code can get a reference to it, because then it wouldn't really
> be read-only!

It's clear, I just want to understand how can I calculate with
memory usage. Imho it's a bit wastefull.


Thanks,


a.