lua-users home
lua-l archive

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


On Wed, Mar 21, 2018 at 2:17 PM, Roberto Ierusalimschy
<roberto@inf.puc-rio.br> wrote:
> This is a nice rational study of the situation. However, there are at least
> two other constructions where we can distinguish the two cases:
>
> 1) Garbage collection of the corresponding key. In your example, can
> 'a' be collected? (We can argue that this case follows from iteration:
> if 'a' appears in an iteration, it must be kept; otherwise, it could be
> removed.)
>
> 2) Metamethods: is 't[a]' "empty" for the point of view of calling
> metamethods? An access to t[a] should call __index? An assignment
> should call __newindex? (This is big difference and independent of
> iterations.)

True, and I am actually quite curious to understand what to do with my
proposal in the scenario 2). Again, to save you a log post: I think
__index and __newindex should be called every time the content is
missing OR it is just nil.

Let's talk about __newindex. Suppose to use a metatable with
__newindex that just log the call and dipatches to rawset.

```
local t = setmetatable({}, meta)
set_normal_mode(t)
t[1] = true -- call __newindex
t[1] = nil  -- __newindex not called
t[1] = true -- call __newindex [1]

local t = setmetatable({}, meta)
set_keep_mode(t)
t[1] = true -- call __newindex
t[1] = nil  -- __newindex not called
t[1] = true -- ? [2]

local t = setmetatable({}, meta)
set_keep_mode(t)
t[1] = true -- call __newindex
t[1] = nil  -- __newindex not called
set_normal_mode(t)
t[1] = true -- ? [3]

local t = setmetatable({}, meta)
set_normal_mode(t)
t[1] = true -- call __newindex
t[1] = nil  -- __newindex not called
set_keep_mode(t)
t[1] = true -- call __newindex [4]
```

The only clear case is [1], since it must behave like the current lua.
[4] also is simple to decide: for how I put the proposal rules, the
content was removed before any set_keep_mode or assignment, so it must
"Call __newindex".

A good reasoning for [2] seems to be: you are in keep-mode, so nil
does not means "empty", so do "Not call __newindex".

For the same reason, in [3] one should "Call __newindex" as in [1].
Just because the table is in normal-mode.

But these behaviours are a bit incoherent: if [2] does "Not call
__newindex" what happended just before [3]? Why the behaviour changes?
It seems that set_normal_mode is not just a flag setting. Does it
immediately remove all the nils? Or in normal mode the nil are removed
also just before an assigment (of a non-nil value!) ? [*]

The main issue I have with all this, is that there are (other)
explicit difference between keep-mode and normal-mode. I would prefer
to keep it as much as possible an implementation detail. In other
words, it breaks the "Empty or Nil? Who cares?" feature.

For these reasons I am more prone to call __newindex in all the
previous cases. And since a similar reasoning can be done with
__index, the full rules set could be:

- Table can act in two mode "Normal mode" and "Keep mode" according to
a flag in its metatable
- Keep-mode tables store nil and it never deletes contents
- Normal-mode tables will deletes contents every times a nil is
assigned or read (as its content).
- __index and __newindex are always called if the content is missing
or it is nil, regardless the table mode.

And I still prefer to not provide any way to directly check empty vs
nil-content, neither for the keep-mode.

Pocomane

[*] Actually, I think that this last option is the second-best solution.