If query does not work for deleted object

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By MaxEl777

In the process functions of an object, I check if another object is null or not null. This other object calls queue_free in itself at some point.
The problem is, that then in the process function the if-query whether the other object is null or not does not work.
I think the reason is that the object is deleted after checking that it is not null.

:bust_in_silhouette: Reply From: jgodfrey

I think you want to check a potentially freed node using:

is_instance_valid(node)

FYI this is not guarantee to work in 3.2 due to an internal design issue: Reference to freed object can return a random different one · Issue #32383 · godotengine/godot · GitHub
It’s been adressed in 4.0. To avoid surprises it’s recommended to architecture game code in such a way is_instance_valid doesnt need to be used, for example querying the path or listening to tree_exited.

Zylann | 2020-04-21 17:38

Hmmm… Good to know. Thanks.

jgodfrey | 2020-04-21 18:44

Thank you very much but I still wonder why I can’t just write
“if node != null”
instead of
“if is_instance_valid(node)?”

MaxEl777 | 2020-04-21 21:32

Because node is a variable containing the memory address of the node. When a node is destroyed, there is no system that sweeps through all possible places in memory where variables point to that node just to set them back to null. (such thing would be quite horrible to implement and very slow). So basically, you can’t have != null do the same on a null value and something else which is clearly not the null value. Besides, it would probably slow down GDScript if is_instance_valid was to run every time you access an object, for the sole purpose of turning it into a null.

Instead, Godot attempts to alleviates this by marking the memory location as “unused”, which is what is_instance_valid checks. But that location can still be re-used later by something else, which is why in 3.2 it may not always work.

Another reason from my point of view, would be that != null and is_instance_valid convey a different meaning in your code.
Checking for null means that you know the variable may or may not have been set.
Checking for is_instance_valid means that you know the variable was set, and that it might have been destroyed.
When reading your code later, this will explicitely show up and remind you why it’s done.
Those are two subtly different scenarios, and sometimes asserting that one of them never happens can help to find design errors in the game logic.

Personally though, I’d try to avoid situations like this as much as I can^^"

Zylann | 2020-04-21 21:40