Deprecating: Returning instances from state objects without a destructor #183
dphfox
announced in
Announcements
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Starting with Fusion v0.2, you may see these warnings in your output.
These warnings indicate deprecated behaviour. As such, we will be converting them to errors starting with Fusion v0.3.
What are destructors?
Destructors are functions which destroy values after you are done with them. For example, you could define a destructor that destroys instances:
Fusion v0.2 allows you to pass these destructor functions into
Computed
,ForKeys
,ForValues
andForPairs
objects. When the state object switches to a new value, the destructor will be called with the old value, so you can clean it up properly.To specify a destructor for any of those objects, pass it in when constructing the object:
For convenience, Fusion will provide two destructors out of the box.
Fusion.cleanup
- cleans up the same way that the[Cleanup]
special key does.Fusion.doNothing
- explicitly specifies that no cleanup should occur, same as writingfunction() end
.When should I use destructors?
If you're working with things that need destruction, you must have a destructor.
You don't need a destructor when working with numbers, for example, because they're simple values. Numbers don't need to be cleaned up after they're used - Lua does that for us!
However, you do need a destructor when working with instances, because if those aren't destroyed properly after use, you could end up with serious memory leaks.
We currently only enforce this with instances. However, we might expand this later to cover:
For both of these things, it's generally a good idea to consider using a destructor anyway, because it makes the intention of your code clear.
Which destructor should I use?
1. If your state object manages the instance, you should use
Fusion.cleanup
.A common example of this is when generating instances inside a Computed callback:
We do not expect any other code to clean up this instance for us. Therefore, this Computed object is responsible for making sure the instance gets cleaned up.
Therefore, we specify
Fusion.cleanup
, to indicate that Fusion should destroy the previous instance when the Computed generates the next instance.2. If your state object does not manage the instance, you should use
Fusion.doNothing
.A common example of this is when referring to instances in the data model, for example getting a list of children for a model:
The Computed object in the example above is not responsible for making sure the instance gets cleaned up. We are merely holding a reference to the instance - if we destroyed the old array of children, then we'd never be able to get a different instance's children without deleting everything!
Therefore, we specify
Fusion.doNothing
, to indicate that Fusion should not destroy the instance whenparent
changes.Why is this important?
If you do not destroy instances after you're done with them, you will cause a memory leak.
This is what destructors exist to solve. They specify whether you intend to destroy something later, and in what way you intend to destroy it.
Here's an example: this Computed object returns an instance. We don't know where it's coming from.
Should we destroy these instances when we're done with them? It's unclear.
If
getInstanceFromSomewhere()
is returning references to existing instances, for example :FindFirstChild(), then we don't want to destroy them. To make this clear, we useFusion.doNothing
explicitly to say 'this should not be destroyed!'On the other hand, if
getInstanceFromSomewhere()
is generating new instances, then we definitely want to destroy them! To make this clear, and to make sure that happens, we useFusion.cleanup
to say 'this should be destroyed!'Considering how destruction should work is very important when working with instances and similar types. However, it could be easy to forget, because remember - destructors are optional. If you forgot to provide a destructor when your code deals with instances, then Fusion has no way of knowing what you intended to do. Therefore, for your safety and sanity as a developer, Fusion emits these warning messages to tell you 'hey! you've given us something that needs destruction, but you haven't told us how to deal with that'.
I find this syntax too verbose. Can we have something else instead?
It's true that perhaps this will make some code longer. However, we think the increased explicitness and attention to detail here far outweighs that negative.
That said, we would love to hear from you! If you have any syntax ideas or ideas for new APIs which could help out with this issue, please do post a feature request here on GitHub. We're all ears and we can't wait to hear what you have to say 🙂
Hopefully this helps you diagnose these issues and fix them appropriately in your codebase. Sorry for the inconvenience, but we're just trying to save you from hours in front of a memory usage debugger!
Beta Was this translation helpful? Give feedback.
All reactions