Is debug.upvalueid()'s result stable?

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

Is debug.upvalueid()'s result stable?

Egor Skriptunoff-2
Lua 5.2+ has function debug.upvalueid(f, n) returning a light userdata.
Does Lua guarantee debug.upvalueid() returns the same result during the lifespan of the closure?

local f = function()....end
local n = ....
local old_id = debug.upvalueid(f, n)
.... GC activity may happen here
local new_id = debug.upvalueid(f, n)
print(new_id == old_id)  -- Is it always true?

Reply | Threaded
Open this post in threaded view
|

Re: Is debug.upvalueid()'s result stable?

Roberto Ierusalimschy
> Lua 5.2+ has function debug.upvalueid(f, n) returning a light userdata.
> Does Lua guarantee debug.upvalueid() returns the same result during the
> lifespan of the closure?
>
> local f = function()....end
> local n = ....
> local old_id = debug.upvalueid(f, n)
> .... GC activity may happen here
> local new_id = debug.upvalueid(f, n)
> print(new_id == old_id)  -- Is it always true?

The documentation says:

   These unique identifiers allow a program to check whether different
   closures share upvalues.  Lua closures that share an upvalue (that
   is, that access a same external local variable) will return identical
   ids for those upvalue indices.

If the identifer changed, it would mean the closure is not sharing the
upvalue with itself. That can actually happen, but only if the program
asks for it:

> local n; function f1 () return n end
> local n; function f2 () return n end
> debug.upvalueid(f1, 1)
  --> userdata: 0x55c0c4f588a0
> debug.joinupvalue(f1, 1, f2, 1)
> debug.upvalueid(f1, 1)
  --> userdata: 0x55c0c4f5a130

-- Roberto
Reply | Threaded
Open this post in threaded view
|

Re: Is debug.upvalueid()'s result stable?

Egor Skriptunoff-2
On Mon, Feb 1, 2021 at 4:42 PM Roberto Ierusalimschy wrote:
The documentation says:

   These unique identifiers allow a program to check whether different
   closures share upvalues.  Lua closures that share an upvalue (that
   is, that access a same external local variable) will return identical
   ids for those upvalue indices.


This quote doesn't answer my question.

A light userdata is just an address of some internal object.
The object's addresses are subject to change during GC activity.
The quote from the manual you've posted might theoretically allow the following situation:

Before GC activity:
> debug.upvalueid(f1, 1)
  --> userdata: 0x1111111100
> debug.upvalueid(f2, 1)
  --> userdata: 0x1111111100

After GC activity (upvaluejoin was NOT invoked):
> debug.upvalueid(f1, 1)
  --> userdata: 0x2222222200
> debug.upvalueid(f2, 1)
  --> userdata: 0x2222222200

At any given moment of time identical ids are returned, as the manual claims.
But the manual promises nothing about how long the result of upvalueid() remains valid.

It is similar to determining if two clocks are synchronized
local time1 = what_time_is_it(clock1)
local time2 = what_time_is_it(clock2)
print(time1 == time2)
A "clock manual" might say:
> The returned values from what_time_is_it() allow a program to check
> whether different clocks share the time.
> Clocks that share the time will return identical values.
But "what_time_is_it(clock1)" might return another value on the next invocation.

In other words, my question is:
Are those hexadecimal digits after "userdata:" permanent?
Reply | Threaded
Open this post in threaded view
|

Re: Is debug.upvalueid()'s result stable?

Roberto Ierusalimschy
> Before GC activity:
> > debug.upvalueid(f1, 1)
>   --> userdata: 0x1111111100
> > debug.upvalueid(f2, 1)
>   --> userdata: 0x1111111100
>
> After GC activity (upvaluejoin was NOT invoked):
> > debug.upvalueid(f1, 1)
>   --> userdata: 0x2222222200
> > debug.upvalueid(f2, 1)
>   --> userdata: 0x2222222200

Lua does not have this notion of "Before GC activity" or "After GC
activity". The GC is active all the time. Lots of things you do in Lua
can create GC activity.  In your particular example, compiling each
line in iteractive mode generates a lot of GC activity. Function calls
can generate GC activity. If you are debugging your code, each hook can
incur GC activity. Printing the identifier also incur in GC activity
(as it creates a string).

The analogy with a clock is apt. You cannot compare two clocks the way
you did, as they can tick together between the two calls. Similarly, it
is very easy for the GC to tick between the calls to 'upvalueid'.  If
any GC activity could change the identifier, it would be really hard to
use 'debug.upvalueid'. (Someone may whine that Lua has other equally
hard-to-use features; that is not the case here.)


> In other words, my question is:
> Are those hexadecimal digits after "userdata:" permanent?

"Permanent" seems a strong word, given that the whole program is
transient; but yes. I hope that a less picky reader can infer that
simply by the use of the word "identifier".

-- Roberto
Reply | Threaded
Open this post in threaded view
|

Re: Is debug.upvalueid()'s result stable?

Viacheslav Usov
In reply to this post by Egor Skriptunoff-2
On Mon, Feb 1, 2021 at 3:44 PM Egor Skriptunoff
<[hidden email]> wrote:

> This quote doesn't answer my question.

Your question was "Does Lua guarantee debug.upvalueid() returns the
same result during the lifespan of the closure?"

Roberto's answer was negative, with a demonstration.

Apparently that was not really the question you wanted answered. You
rephrased your question:

> Are those hexadecimal digits after "userdata:" permanent?

But the answer to this is trivially negative again, from the same demonstration.

I may have misunderstood, but it looks like you are asking for a full
list of operations that could change a previously seen upvalue ID for
a given contiguously existing chunk.

I do not know the (full) answer, but GC is not part of it, because
Lua's (stock) GC is non-moving, so an address of an existing object
cannot change. I would think that the upvalue join demonstrated by
Roberto, along with its C API counterpart, should be the only such
operation, but somebody more knowledgeable should confirm this.

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

Re: Is debug.upvalueid()'s result stable?

Egor Skriptunoff-2
On Mon, Feb 1, 2021 at 8:05 PM Viacheslav Usov wrote:
it looks like you are asking for a full
list of operations that could change a previously seen upvalue ID for
a given contiguously existing chunk.

I was asking whether a GC activity could change a previously seen upvalue ID.


Lua's (stock) GC is non-moving.

The manual does not promise this.
That's why I have posted my question.
I was not asking about GC implementation details.
I was interested in what Lua does guarantee about upvalue ID.