Create a "weak reference"?

Is it possible to create a “weak reference”, a weak table but instead of the entire table being weak it’s just a single key/value

I have 2 classes, Class1 and Class2. Class1 references Class2, so when Class2 gets destroyed it won’t be GCd because of the reference in Class1

local Class1 = Class.new()
local Class2 = Class.new()

Class1.SignalClass = Signal.new() --This is the only reference to this "signal" object, so I cannot make Class1 a weak table
Class1.AnotherClass = Class2 --I want this to be a "weak reference"

Class2:Destroy()
Class2 = nil --Won't get GCd

No, table keys/values are either all weak or not.

Personally I would use setters/getters for this scenario. I think hiding the weakness of a reference behind an assignment has the potential to confuse the user of your module (which might be yourself :slight_smile: ).

If you really wanted to though, I suppose you could hide the implementation from the user with __newindex. It might require a bit of a different approach to your OOP though, since the metatable is defined in the object creation itself.

-- untested but makes sense to me :)

local Class = {}
-- removed on purpose, see later comments
-- Class.__index = Class

local Class_WEAK_KEYS = {
    "AnotherClass" = true,
    "AnotherWeakKey" = true
}

function Class.new()
    local weakRefs = setmetatable({}, {
        __mode = "v" -- or "kv" depending on your needs
    })
    
    setmetatable(obj, {
        __index = function(t, k)
            if Class_WEAK_KEYS[k] then
                -- return weak reference instead
                return weakRefs[k]
            else
                -- replaces the usual Class.__index = Class that you see
                -- in some OOP implementations
                return Class[t]
            end
        end,
        __newindex = function(t, k, v)
            if Class_WEAK_KEYS[k] then
                -- assign weak reference instead
                weakRefs[k] = v
            else
                rawset(t, k, v)
            end
        end
    })
    
    return obj
end