Lua weak reference
Asked Answered
L

2

11

I'm aware of the weak tables functionality in Lua, however I would like to have a weak reference with a single variable.

I've seen this proposal which suggests an API as follows:

-- creation
ref = weakref(obj)
-- dereference
obj = ref()

which would seem ideal. However this doesn't appear to be in the documentation elsewhere; only weak tables.

Is there something analogous to Python's weak reference to object functionality?

Louvain answered 17/3, 2015 at 21:6 Comment(7)
What are you trying to do here ultimately? You can emulate this yourself using a table with at metatable I believe (or with newproxy and a metatable) if you really need to.Scrutineer
I'm using middleclass for OO, passing a closure from objA to objB. When objA goes out of scope, the closure is preventing both instances from being GC'd because it contains a reference to objA. Never heard of newproxy before, going to google it up...Louvain
hmmm.. "The undocumented newproxy function was removed in Lua 5.2, since it was made redundant by other features added in that version" from lua-users.org/wiki/HiddenFeaturesLouvain
Yeah, you don't need it for this it was just to use a userdata instead of a table for the idea. The idea was a table with a metatable which supported __call to get you the ref() syntax where either the table itself or the metatable were weak and held the reference.Scrutineer
Interesting.. I've not used metatables too much with Lua. I'll have a read to see if there's something useful there. Thanks.Louvain
You don't need the metatable for the weak-ref idea. Without it you just need to use ref.real or ref.obj or whatever instead of ref().Scrutineer
"this proposal" is a document from 2004, before you could (I presume) create weak tables directly in Lua (i.e., without using the C API). That's no longer the case nowadays. You got two good answers showing you how to do this.Scurlock
S
5

Something like this can do what you want I believe:

local obj = {value = "obj.value"}

local ref = setmetatable({real = obj}, {__mode = "v", __call = function(self) return self.real end})

print(obj.value)
print(ref.real.value)
print(ref().value)

obj = nil
collectgarbage()
collectgarbage()

print(obj)
print(ref.real)
print(ref())

The __call part is optional but gives you the ref() call syntax. Without it you have to use the direct access version.

Scrutineer answered 17/3, 2015 at 22:16 Comment(0)
V
10

When lua does not provide something, there is often a simple way to implement it from the other primitives.

function weakref(data)
    local weak = setmetatable({content=data}, {__mode="v"})
    return function() return weak.content end
end

We create a weak table with just the data in it. Then we return a function that when called, returns the contents of that table.

(Note, weak references may not be broken until garbage collection, and literals are never garbage collected.)

Vastah answered 17/3, 2015 at 22:15 Comment(3)
It's a shame this answer wasn't accepted - it's better than the accepted one, AND came about a minute sooner.Adalai
The other answer has some pretty important things going for it... specifically, it has the potential to create less garbage, since my solution creates an object and a closure over that object for each call, while the accepted solution only creates the table. (Both also spuriously create a new metatable each time as well, but that could be pulled out and reused).Vastah
Ah, good points. Mostly I just needed to learn about __mode="v" - in my use case I'm making an image pool and just wanted a weak table where all the values in a table were collectable.Adalai
S
5

Something like this can do what you want I believe:

local obj = {value = "obj.value"}

local ref = setmetatable({real = obj}, {__mode = "v", __call = function(self) return self.real end})

print(obj.value)
print(ref.real.value)
print(ref().value)

obj = nil
collectgarbage()
collectgarbage()

print(obj)
print(ref.real)
print(ref())

The __call part is optional but gives you the ref() call syntax. Without it you have to use the direct access version.

Scrutineer answered 17/3, 2015 at 22:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.