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
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.
null means that you know the variable may or may not have been set.
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^^"