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^^"