About WeakRefs

A question came up recently about WeakRefs so I thought I’d post something to help with understanding and using them. I have a longer, more detailed post elsewhere on the forum if you’re interested.

When you create an object, say a Dictionary, divorce in your mind the object from the variable or property that holds it. The object is out there somewhere and the variable is your bridge to it.

dim GoldenGate as new Dictionary

You can assign that object to more than one variable/property, and that creates more bridges, but there is still only one object.

dim GoldenGate as new Dictionary
dim Brooklyn as Dictionary = GoldenGate
dim Williamsburg as Dictionary = Brooklyn

When there are no more ways to access the object, that is, when all the bridges are gone, the object goes away.

dim GoldenGate as new Dictionary // 1 bridge
dim Brooklyn as Dictionary = GoldenGage // 2 bridges

GoldenGate = nil // Well, one bridge left
Brooklyn = nil // All bridges gone, the object is destroyed

This is known as “reference counting”. When a variable refers to an object, there is a reference and the object sticks around. When there are no more references, the object is destroyed.

But there are times when you want to be able to access an object without creating a reference to it. In other words, you want to be able to test to see if an object still exists, and create a reference to it if it does, without forcing it to stick around. In this example think of it as a string to the object. If there are other bridges to the object, the string will lead you to it too and let you build a bridge. If all the bridges are gone, the string snaps and leads nowhere.

For these times, Xojo has offered the WeakRef. A WeakRef, or weak reference, will let you get to an object without forcing it to stick around in memory if the rest of your code is done with it.

dim d as new Dictionary // the object has one reference
dim w as new WeakRef( d ) // still one reference
dim d1 as Dictionary = Dictionary( w.Value ) // Now two references
d = nil // Back to one reference, w.Value <> Nil
d1 = nil // No more references, w.Value = Nil

In the next post, I’ll offer examples of how this is useful.

So when might you want a WeakRef instead of merely assigning the object to another variable?

The most common use is to prevent a circular references, that is, an object that holds a second object where the second object holds the first object. With a circular reference, you can lose access to an object that will never be destroyed and create a memory leak.

The most common scenario here is the parent/child relationship. Lets say you create a Tree class that can hold many Leaf classes in an array. From any Leaf, you want to be able to get back to its Tree. That is, the Tree is the parent and the many Leaf’s are its children. Consider this simple example where a Tree has a single Leaf:

dim t as new Tree
dim l as new Leaf

t.Child = l
l.Parent = t

t = Nil
l = Nil

Even though we’ve set both variables to Nil, both still exist because each refers to the other. To prevent that, you’d have to change the code that gets rid of the objects to something like this instead:

t.Child = Nil
t = Nil // The Tree object sill exists because l.Parent refers to it
l = Nil // No more references to the Leaf, and since it's gone, no more to the Tree either

But there is an easier way. Instead of defining Leaf.Parent as a Tree, define it as a WeakRef instead.

dim t as new Tree
dim l as new Leaf

t.Child = l
l.Parent = new WeakRef( t )

l = Nil // The Leaf still exists because t.Child refers to it
t = Nil // Since t was the only reference, Tree goes away and takes Leaf with it

A Computed Property in Leaf that handles the WeakRef mechanics makes the process painless. But either way, since the only “true” reference is of the Parent to its Child, the problem of the Circular Reference evaporates.

In the next post, I’ll offer a different example.

Imagine code that sends objects through queues. While an object is waiting to be processed something might happen that renders it invalid or unnecessary. How to handle that?

For example, suppose there is a UI where the user can click off multiple items where each item represents an object that is placed on a queue for processing. After the user has ticked off multiple objects, they change their mind and uncheck a few. How to take them off the queue?

You could search the queue for that object and delete it. But what if your code uses multiple queues? What it you might add more in the future? This can all be solved easily with a WeakRef.

The main array holds your objects and each queue holds a WeakRef to that object. When it comes time to process an item in the queue, the code resolves it back to its original object. If it can’t, that is, the WeakRef evaluates to Nil because there are no other references to it, the queue processor ignores it and moves on. In this scenario, you can remove the object from every queue at once by simply deleting it from the main array. Bang, no more references to the object, so no more object, and the queues simultaneously have empty placeholders in the slots that originally represented that object.


I hope someone finds this helpful. If you have other real-world examples, please post them.

I use WeakRefs to ovoid circular relationships between classes.

A “Parent” object uses strong references to hold on to it’s “Children”.

A “Child” object uses a WeakRef for it’s relationship to it’s parent.

I think you scrolled past my second post. :slight_smile:

Great post Kem. Switching to WeafRefs for the parents in my tree structure in the Markdown parser I’m working on right now.

Excellent stuff @Kem Tekinay, It’s a shame there’s no knowledge base to keep this current. Perhaps @Xojo User might link to this conversation from the docs.

Awesome post, Kem!

Kem,

post was kinda weak :wink:

Thanks for the information!

Along with “like”, we need a “slap” option.

:stuck_out_tongue:

Yes, this kind of very useful education should be kept somewhere. For now, I capture Kem’s ‘masterclass’ in my personal KB.
@Kem Tekinay I encourage you to join @Paul Lefebvre for some great webinars.

@Paul Lefebvre has turned this post into part of the online User Guide. See:

https://documentation.xojo.com/topics/advanced_features/creating_weak_references_to_objects.html

yeah tis all wrong anyways

j/k :stuck_out_tongue:

slap

fine - back to my cave then

but it could be a great reference

SLAP!!

OW !!!

I’d liken it to you being out with parents & kids
if you hang on to each of them by their shirts they cant go anywhere as long as you hold on
and maybe several parents are hanging on to the same kids so if you let go the kid still cant run off

but if you hang onto a kid who you entrust to hang onto another kid and they let go of that kid and no one else is hanging on to them well … that other kid could be long gone
you might still have a hold of the first kid (the weakref) but what it holds onto is gone
and you might not know until its too late

that said this should also spur some notes about AddressOf and WeakAddressOf as they are VERY similar - except with WeakAddressOf you have NO way to even tell if the ultimate target is gone - it just can be and your app dies

i think i ran into comprehension issues with weakref and WeakAddressOf when setting up callbacks for embedded objects.