Are cyclic references between objects a bad practice?

Hello Devforum,

I’ve recently been designing a framework and some of the objects within it have cyclic references to “parent” objects. Here’s a generalized example:

Example
function ObjectB.new(GivenObjectA)
    local self = setmetatable({}, ObjectB)
    
    self.LinkedObjectA = GivenObjectA
    self.Name = "ObjectB" 

    return self
end

function ObjectA.new()
    local self = setmetatable({}, ObjectA)
    
    self.LinkedObjectB = ObjectB.new(self)
    self.Name = "ObjectA"
    
    return self
end

local NewObject = ObjectA.new()
print(NewObject.LinkedObjectB.Name) -- "ObjectB"
print(NewObject.LinkedObjectB.LinkedObjectA.Name) -- "ObjectA"

I’m wondering if this would harm performance, memory usage or are simply a bad code smell when I use methods such as this. I’m pretty comfortable with this method because it makes it quite easy to program with and to navigate, though I’m wondering if such references clog up memory every time it’s stored in a local variable, for example?

I was wondering if I could think of anywhere else that does this, and I realized Roblox has this fundementally in instances, where with :GetChildren() you can get an Instances child, which can be referred to again with child.Parent, which is, in a way, cyclic?

I was thinking of a method where instead I could add a function to the object, :GetLinked() which returns the linked object removing the need to store it in the parent object.

TLDR: Are cyclic table references harmful to performance, cleanliness or a code smell?

If anybody has any advice or experience with this, all help is appreciated.

Thank you!

2 Likes

It’s not neccessarily bad. In some graph problems it isn’t possible to avoid cyclic references. The references themselves do not cost anything, but a cyclic reference will stop the items in the cycle from being garbage collected. To avoid that, you should have a specific way of removing objects that makes sure it doesn’t create any dangling objects. Cycles also complicate writing any code that has to “walk” those references, it means you must keep track of what objects you already visited.

2 Likes