Array, strange behavior

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

var a:Array =
var b:Array =

func _on_Button_pressed():
a.append(0)
a.append(1)
a.append(2)
b.append(a)

func _on_Button2_pressed():
print(a) #result = [0, 1, 2]
print(b) #result = [[0, 1, 2]]
a.clear()
print(a) #result =
print(b) #result = []

func _on_Button3_pressed():
a.append(3)
a.append(4)
a.append(5)
print(a) #result = [3, 4, 5]
print(b) #result = [[3, 4, 5]]

Is this kind of behavior normal?

:bust_in_silhouette: Reply From: Bernard Cloutier

That is indeed normal. What was the behaviour you expected?

Here is what’s happening:

Arrays in gdscript can hold a number variants, that is to say any gdscript type (int, float, bool, string, Object, etc.). The append method means: take this and insert it at the end of the array. Whatever “this” is will be inserted. However, for simple built-in types (int, float, bool, string, vector2…), that means copying their values. For object types (arrays, nodes, other custom types inheriting from Object…), that means copying a reference to that object. That reference is why when you modify array a, the array a that was inserted in array b also gets modified (since it is the same object and not a copy).

I feel that you meant the line b.append(a) to result in b containing [0, 1, 2] instead of [[0, 1, 2]], right? To obtain this, you’d have to iterate through a and copy each individual element, like so:

func _append_array(target, source):
    for elem in source:
        target.append(elem)

[Tip: use the curly braces {} icon to get code formatting in your selection]

I was curious because “b.clear()” behaves in one way and “b = ” behaves in another. The first, by the way, eliminates all traces of “b”, even being inside others vars. The second one cleans only “b”.
The confusing thing is that if I put “b” inside “a” (a.append (b)), and then clear “b” with “b.clear()”, any changes I make to b will change it inside a (including b = ). Now if I don’t use .clear () I can do whatever I want with b that doesn’t influence in “a”. This is the behavior that I found strange.

Firty | 2020-02-28 21:22

func _on_Button4_pressed():
a.append(6)
a.append(7)
a.append(8)
b.append(a)
print(a) #result = [6, 7, 8]
print(b) #result = [[6, 7, 8]]
a =
print(a) #result =
print(b) #result = [[6, 7, 8]]

It is as if only this “.clear ()” creates a connection between the two vars.

Firty | 2020-02-28 21:29

You have to remember that in case of objects, the symbols (aka the names of your vars) are references to an in-memory object.

a = [1, 2, 3] means “Create the array object [1, 2, 3] and make a refer to it”.

b = [] means “Create the array object and make b refer to it”.

b.append(a) means “Take the object pointed to by a and add a reference to it at the end of the array pointed by b”.

If you’re following, you’ll see that both a and the first item in the array pointed to by b refer to the same object, the array [1, 2, 3].

Now if you do: a.clear(), the “clear” method will be applied to the array [1, 2, 3], which is also being referenced in the array pointed to by b. That is why you are seeing the change, not because the clear method creates some sort of magical “connection”.

If you instead do: a = [], you are saying: “Create another array containing nothing and make a refer to it”. You won’t see any change in b, because you’ve only changed what a points to. Remember that b doesn’t hold a reference to a, it only held a reference to the array pointed to by a, which is still in memory somewhere and is now only being referenced by the first item of the array pointed to by b (since a now points to another array object).

In comp sci, we often talk about passing by value or by reference. In the case of gdscript, see this line from the docs:

In GDScript, only base types (int, float, string and the vector types) are passed by value to functions (value is copied). Everything else (instances, arrays, dictionaries, etc) is passed as reference.

source: GDScript: An introduction to dynamic languages — Godot Engine (stable) documentation in English

Bernard Cloutier | 2020-03-02 13:42