__close: presence and time of evaluation

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

__close: presence and time of evaluation

Viacheslav Usov
The current 5.4 beta manual states:

The value assigned to a to-be-closed variable must have a __close metamethod or be a false value.

(end)

This very likely implies that the __close metamethod must be present at the time when the value is assigned to the variable. If this is indeed the expectation, then it would be good to have it stated more explicitly. The manual does not specify the behavior for the case when the metamethod is absent. It would also be good to have an explicit statement of that.

Then, it may be inferred that when the variable is being closed, the originally seen value of __close will be called, i.e., changes to the value of __close in the metatable will not be effective. If this is what is indeed implied, it would be good to see that stated as such in the manual.

On the other hand, I would like to say that the above seems like an unnecessary complication that could be wholly removed if the manual said instead of the cited sentence (and the behavior matched): 

When a variable is being closed, the current value of the __close metamethod, if any, is used.

(end)

This makes it possible to "close" anything, without that having any effect (except in performance perhaps) and change what closing will do during the lifetime of the variable. I think this will also save a few CPU cycles in the ordinary case when closing has an effect.

Note that unlike the __gc case, where there is no natural way for the VM to learn that a value should be marked for finalization, and __gc is checked when a metatable is assigned, <toclose> in the local declaration tells the compiler explicitly that closing is requested, so there is no real need to check for __close at this point.

Cheers,
V.
Reply | Threaded
Open this post in threaded view
|

Re: __close: presence and time of evaluation

Roberto Ierusalimschy
> Then, it may be inferred that when the variable is being closed, the
> originally seen value of __close will be called, i.e., changes to the value
> of __close in the metatable will not be effective. If this is what is
> indeed implied, it would be good to see that stated as such in the manual.

If someone sets a to-be-closed variable with a value with a given
__close, and than they change that __close before the value is closed,
and they cannot figure out which one will be called, it seems healthy
to keep them ignorant about that.

-- Roberto

Reply | Threaded
Open this post in threaded view
|

Re: __close: presence and time of evaluation

Viacheslav Usov
On Fri, Oct 4, 2019 at 8:58 PM Roberto Ierusalimschy <[hidden email]> wrote:

> If someone sets a to-be-closed variable with a value with a given __close, and than they change that __close before the value is closed, and they cannot figure out which one will be called, it seems healthy to keep them ignorant about that.

In the case of __gc, you seem to think otherwise.

Regardless, the current behavior with respect to the presence and time of evaluation of __close seems unnecessarily complicated. Can you explain what is gained by having to check the validity of __close twice? In the first check, luaF_newtbcupval() obtains the metamethod just for the sake of checking that it exists, it is not used nor stored for later use. In the second check, callclosemth() does not seem to have a real need to raise an error if there is no __close, which it actually does not do if another, seemingly arbitrary, condition is satisfied.

So, as far as I can tell, lines 155, 156, 199, 200 and 201 of lfunc.c (of 5.4.0-beta-rc1) can be deleted without breaking anything. The resultant behavior is then simple: any local can be marked for closing; such locals are constant; when leaving the scope of a local thus marked, the __close metamethods of its value, if present, will be called. Note that this behavior is more alike that with __gc, when it is not an error that an object previously marked for finalization does not have a __gc when finalization begins.

Cheers,
V.
Reply | Threaded
Open this post in threaded view
|

Re: __close: presence and time of evaluation

Viacheslav Usov
On Sat, Oct 5, 2019 at 11:53 AM Viacheslav Usov <[hidden email]> wrote:

> In the first check, luaF_newtbcupval() obtains the metamethod just for the sake of checking that it exists, it is not used nor stored for later use.

I missed that the error handling branch that follows depends on this check and calls callclose() unconditionally, which is easy to fix.

Cheers,
V.
Reply | Threaded
Open this post in threaded view
|

Re: __close: presence and time of evaluation

Roberto Ierusalimschy
In reply to this post by Viacheslav Usov
> Regardless, the current behavior with respect to the presence and time of
> evaluation of __close seems unnecessarily complicated. Can you explain what
> is gained by having to check the validity of __close twice? [...]

In our (short) experience, the check in the initialization detects
several mistakes in the code and gives clearer error messages.

-- Roberto

Reply | Threaded
Open this post in threaded view
|

Re: __close: presence and time of evaluation

Xavier Wang
Roberto Ierusalimschy <[hidden email]> 于2019年10月7日周一 下午10:28写道:

>
> > Regardless, the current behavior with respect to the presence and time of
> > evaluation of __close seems unnecessarily complicated. Can you explain what
> > is gained by having to check the validity of __close twice? [...]
>
> In our (short) experience, the check in the initialization detects
> several mistakes in the code and gives clearer error messages.
>
> -- Roberto
>
After a simple try it seems that when __close changed to nil, the
runtime error still has good information:

> local a <close> = setmetatable({}, {__close = true}); getmetatable(a).__close = nil
stdin:1: attempt to close non-closable variable 'a'
stack traceback:
stdin:1: in main chunk
[C]: in ?

But if remaining __close as boolean, the error message looks messy:

> local a <close> = setmetatable({}, {__close = true})
stdin:1: attempt to call a boolean value
stack traceback:
stdin:1: in main chunk
[C]: in ?

Is there any reasons for not mention the name of to-be-closed variable
when the __close metamethod is not callable?

--
regards,
Xavier Wang.