Make builtins retrieved from a container immutable ?
I've worked a bit on issue #61, and I've discovered a strange behavior about Godot containers.
Considering a godot array containing mutable builtin data (e.g. Vector2) here is what we got in memory:
Array -> ArrayPrivate -> Vector<Variant>
In a nutshell Array is a thin wrapper around a pointer on ArrayPrivate (this is convenient given Array is itself often allocated on Variant internal memory, so it's cheap to have multiple Variant all referencing to the same array data).
The ArrayPrivate itself is a proxy structure doing ref counting on the Vector<Variant> (note this not a std::Vector but a custom Godot Vector)
So in the end the array data are hold inside a Vector (so contiguously allocated memory container). The thing is this Vector structure is not frozen (quiet the opposite really !): it supports resizing and copy-on-write which means there is no guarantee a pointer on one of it elements will still be valid in the future !
The issue brought by this architecture can be seen in the following GDscript snippet:
var a = [Vector2()]
a[0].x = 42
var b = a[0]
b.x = 43
print(a) # Returns [Vector2(42, 0)]
# Same behavior with Dictionary and Pool*Array :'-(
We can modify an array entry's data if we do it in a one-liner such as a[0].x = 42 given this allow to do atomic access&modification of an element in the Vector.
On the other hand doing it in two times (getting the array item with var b = a[0], then modifying it with b.x = 42) won't modify the array item given a copy of the item has occurred in the meantime (inital Vector2 was stored in the Vector, new one is stored inside a Variant present on the GDscript interpreter's stack.
This is a really disturbing behavior from a Python user point of view where every object is passed by reference.
To fix this I'm considering turning immutable the builtins that have been retrieved from a container.
I would have been more convenient to make all builtins immutable, but this would prevent from doing useful things like player.pos.x += 10
Obviously bultins that only keep a pointer on a proxy object (Array, Dictionary and Pool*Array) would still be mutable.