Null safety and memory, 2 of 5
Reference counting and lifetimes
See exactly when an object is freed, and use Destroy to clean up as it goes.
What you’ll build
A Connection Class that says when it opens and when it closes, used in a few ways: inside a
function, shared between variables, and kept in an array. Its messages show when each object is
freed, which in FutureBlitz is a fixed point in the program, not whenever a collector runs.
Freed when the last reference goes
Every object counts the references to it: variables, fields, array elements, and captures. When
the count reaches zero, the object is freed at once, and its Destroy Method runs first, if it
has one. A Local’s reference goes when its block ends, so an object made in a function and not
kept is freed when the function returns.
Import std.core
Class Connection
ReadOnly Field Name: String
New(name: String)
Name = name
Print("open {name}")
End New
Method Destroy()
Print("close {Name}")
End Method
End Class
Function Query()
Local connection = Connection("query")
Print("using {connection.Name}")
End Function
Query()
Print("after Query")open query using query close query after Query
There’s no Delete: code can’t free an object while something still refers to it, so no
reference ever points at freed memory. Only the raw pointers of Unsafe code, used with C
libraries, can.
Shared objects live as long as any reference
Two variables that share an object each hold a reference. Giving one of them a new object takes away only its own reference, and the old object stays while the other still holds it.
Import std.core
Class Connection
ReadOnly Field Name: String
New(name: String)
Name = name
Print("open {name}")
End New
Method Destroy()
Print("close {Name}")
End Method
End Class
Local primary = Connection("first")
Local backup = primary
primary = Connection("second")
Print("primary replaced")
backup = Connection("third")
Print("backup replaced")
Print("end of program")open first open second primary replaced open third close first backup replaced end of program close third close second
first closes only when backup, its last reference, takes a new object. When the program ends,
its variables let go of what they hold, the last declared first, which closes third, then
second.
Collections hold references too
An array, a Map, or any collection holds a reference to each object in it. Removing an object, or clearing the collection, lets it go.
Import std.core
Class Connection
ReadOnly Field Name: String
New(name: String)
Name = name
End New
Method Destroy()
Print("close {Name}")
End Method
End Class
Local pool = [Connection("a"), Connection("b"), Connection("c")]
pool.RemoveAt(0)
Print("removed a")
Local kept = pool[0]
pool.Clear()
Print("cleared, still holding {kept.Name}")close a removed a close c cleared, still holding b close b
Destroy for cleanup
Since the moment an object goes is known, Destroy is a reliable place to give back what the
object holds, like a file, a socket, or a lock. It takes no parameters, can’t be called directly,
and runs on every object of its Class. A Class that extends another runs its own Destroy
first, then the other’s.
Import std.core
Class Connection
ReadOnly Field Name: String
New(name: String)
Name = name
End New
Method Destroy()
Print("close the connection {Name}")
End Method
End Class
Class SecureConnection Extends Connection
Method Destroy()
Print("end the session of {Name}")
End Method
End Class
Local link = SecureConnection("bank")
link = SecureConnection("shop")
Print("done")end the session of bank close the connection bank done end the session of shop close the connection shop
Destroy is never marked Override: every Class’s own runs.
What you learned
- An object is freed the moment its last reference goes, and its
Destroyruns then. - Variables, fields, collections, and closures all hold references.
- There’s no
Delete, so outsideUnsafecode no reference can point at a freed object. Destroycleans up what an object holds; a Class and the Class it extends each run their own, the most derived first.
The rules are in the language reference.
Report an issue with this page or with FutureBlitz on GitHub.