Describe the project you are working on:
I have a large solar system simulation where bodies are generated procedurally (from data tables) and can be saved/loaded using our Procedural Saver/Loader (in the Asset Library).
Describe the problem or limitation you are having in your project:
If a and b are arrays, I need a GDScript method to test if a and b are the same array. (Currently, a == b tests whether they have the same content.) Also, if a, b, c are different arrays, I need to be able to use them (or some value derived from them) as unique dictionary keys.
The reason I need this is to generalize our Procedural Saver/Loader to handle arrays that are referenced in >1 location. I'm all set for objects and dictionaries (since different objects or dictionaries act as unique dictionary keys) but I'm stuck on arrays.
This limitation is discussed in issue #33627. But it's labeled as discussion, not bug. And no workarounds have been proposed there.
Here's some code to show the different treatment of arrays and dictionaries.
print([] == []) # prints true
print({} == {}) # prints false
var a := []
var b := []
var dict_w_array_keys := {}
dict_w_array_keys[a] = 1
dict_w_array_keys[b] = 2
print(dict_w_array_keys.size()) # prints 1
var c := {}
var d := {}
var dict_w_dict_keys := {}
dict_w_dict_keys[c] = 1
dict_w_dict_keys[d] = 2
print(dict_w_dict_keys.size()) # prints 2
# objects behave like dictionaries in all tests above
Describe the feature / enhancement and how it helps to overcome the problem or limitation:
My preference is for == to work for arrays as it does for dictionaries and objects. That is, an identity test, not a content test. Relatedly, two different arrays should act as unique keys in a dictionary, regardless of content.
Alternatively, without changing the way "identity" currently works in arrays, I propose methods to test true array identity and to obtain unique array identifiers suitable for use as dictionary keys.
Either of these approaches will allow me to generalize Procedural Saver/Loader to operate on arrays the way it currently does for objects. Specifically, we can know if we are looking at a non-yet-encountered array versus an already-saved array in our save code.
Describe how your proposal will work, with code, pseudocode, mockups, and/or diagrams:
My preferred solution will break existing projects:
== for arrays to be an identity test (not content test) as it is for dictionaries & objects.is_equivalent_arrays(a, b) to test array content, replacing existing == functionality.Alternative solution (non-breaking):
is_same_array(a, b) to test array identity.Array.get_id() or Array.get_ref() that provides some sort of unique identifier for each array. I don't care what that identifier is as long as it works as a unique dictionary key. I believe that is what the original poster in issue #33627 is asking for by an array "reference".Note: the 2nd point above is really the key to Procedural Saver/Loader's operation. It uses dictionary indexing to know when it is looking at a not-yet-encountered object versus an already-saved object during a game save event. To generalize this to work for arrays too, I'd need the same capacity.
If this enhancement will not be used often, can it be worked around with a few lines of script?:
Well, sort of. I can make arrays identifiable by appending an id to every array in the project, then removing that id when Procedural Saver/Loader is done. It's inelegant and inefficient for a large save with many 1000s of arrays.
Is there a reason why this should be core and not an add-on in the asset library?:
I don't think it's possible to add this capability as an add-on.
Currently the fact that dictionaries are not compared by content is a major (-ish) pain point in the core.
So, I'm much more inclined to having another operator or method which checks for reference equality between two arrays or dictionaries.
Given that there was some reference-related stuff added to PackedXArray-s, I guess such an operator might be useful to compare their identities as well.
I edited my post for clarity. I'm happy either way: change arrays to act like current dictionaries (== is identity test and arrays become unique keys) or change dictionaries to act like current arrays (== is content test and dictionaries are no longer unique keys).
But if the latter, we really need some kind of array/dictionary referencing system available in GDScript.
Consistency with PackedXArrays would also be desirable.
Just to give my vote. Definitely would like to have some way to check if arrays are equal. Was surprised that == actually compared the contents instead of reference. In terms of solutions, in the long term would prefer == and dictionary-key and such to work by reference (so maybe in Godot v4..?). But, in the short term, would just like some way to check for identity, so prefer your alternative solution: is_same_array(a, b) as a quick fix. (Just because changing the operator and key behaviour would surely cause trouble.)
Also found this: 27615
Hi there, I'm coming from https://github.com/godotengine/godot/pull/35816#issuecomment-711028201 ;-)
Array.id()/Dictionary.id() is pretty close to your need (the only trouble is id() returns NULL when the array/dictionary is empty, so you cannot directly do is_different = a.id() != b.id())
Array/Dictionary.id() are not used in the codebase (I've recompiled Godot fine with them stripped), hence I guess we can slightly modify it implementation to fix the NULL-on-empty issue:
// current implementation
const void *Array::id() const {
return _p->array.ptr();
}
// new implementation
const void *Array::id() const {
return _p;
}
This way we could just expose this method to GDScript and have a neat way to compare by ref o/
I'm willing to work on this (it's pretty close to my PR on array/dictionary comparison)
Most helpful comment
Hi there, I'm coming from https://github.com/godotengine/godot/pull/35816#issuecomment-711028201 ;-)
Array/Dictionary.id()are not used in the codebase (I've recompiled Godot fine with them stripped), hence I guess we can slightly modify it implementation to fix the NULL-on-empty issue:This way we could just expose this method to GDScript and have a neat way to compare by ref o/
I'm willing to work on this (it's pretty close to my PR on array/dictionary comparison)