:Destroy() and culling references, seperate things!

I’m trying to remove an object outright, AnimationTrack.
I can call :Destroy() on the object and it’ll be removed, the connections will break, and that is that.
Until I call ;

AnimationTrack:Play()

And then the animation continues to play! Oh noe!
In which case, I’ll null the reference to it.

AnimationTrack:Destroy()
AnimationTrack = nil
AnimationTrack:Play() --We will now error, as AnimationTrack is nil!

However, over the course of creating the animation track, an additional reference has been created.

AnimationTrack2 = AnimationTrack
AnimationTrack:Destroy()
AnimationTrack = nil
AnimationTrack:Play() --We will now error, as AnimationTrack is nil!
AnimationTrack2:Play() --We won't error! We have to manually null again!

Which brings up something I didn’t realize before, calling :Destroy() on an object doesn’t null all references to it, just locks some functionality until all references to it are nulled. Originally I had assumed this was the behavior of :Remove(), but :Destroy() still allows references to remain.

I understand that calling AnimationTrack = nil would nullify the reference, but if I have multiple scripts or multiple references to an object, without creating an additional system for all this, is there nothing I can do to make sure that they also get removed?

Unfortunately no.

You would have to keep track of all references. Though I must question why would you have another reference to the animation track?

This makes sense since your variable contains reference to the track, Roblox would probably have to null the variable from the stack/environment or something which is heavily intrusive to code imo.

This is what maid classes are for.

I pass the AnimationObject, the AnimationController, and some other variables over to a module.
The module takes that, creates not only the animation track, but based on the variables also creates various connections.
I then have two ways of ending that Animation and destroying all its associated variables;
KillAnimation(AnimationTrack), goes through the table and obliterates the variables
KillController(AnimationController), finds all the animation tracks of the controller, then calls KillAnimation on them all.

Both can be fired independently, or -again based on variables- when the animation stops.

Often we create manager object to handle setup, access and removal so it it fits your needs create one.

The only difference between :Destroy() and :Remove() is that :Remove() allows the parent to be changed as it has not been locked.

In most cases references fall out of scope meaning they are GC. If you are setting veriables to nil often then rethink your code. This could mean you need to break down the code into additional functions or use another module to share content.

1 Like

I think I’ve missed a lot of this because I’ve been using OOP for a ton of things.
This is one of my few times coming back to a purely function based module.

The only other thing I can think of would be to use a weak table but that can become complex to manage and difficult to debug.

References to instances are always strong, so a weak table won’t ever dispose of Instances properly.

Edit: Quote from somebody smarter than me who explains it better:

4 Likes

To solve the immediate problem, I’ve change the module to return nothing, and use the AnimationObject as a reference. I can grab it via the actual object or the controller’s AnimationTracks, so I don’t need to hold a reference to the track anymore.

Edit: Actually, this has shaped the module into a slightly more user friendly direction! :smiley:
Improvise. Adapt. Overcome.

2 Likes