godot icon indicating copy to clipboard operation
godot copied to clipboard

Exported dictionaries have their keys sorted alphabetically

Open JHDev2006 opened this issue 1 year ago • 9 comments

Tested versions

  • Tested with Godot 4.1.2 and Godot 4.3 dev 5

System information

Godot v4.3.dev5.mono - Windows 10.0.22631 - Vulkan (Forward+) - dedicated NVIDIA GeForce RTX 3070 Ti (NVIDIA; 31.0.15.4592) - AMD Ryzen 7 5800X 8-Core Processor (16 Threads)

Issue description

When an exported dictionary is created, they keys which are set in the editor, are sorted at runtime, which is incredibly frustrating for my use case.

Steps to reproduce

  • Create an exported dictionary (@export var dict := {})
  • Add some values into the dictionary through the editor. - ({"b": 0, "c": 1, "a": 2})
  • Print the dictionary, it will output: "{"a": 2, "b": 0, "c": 1}"

Minimal reproduction project (MRP)

N/A

JHDev2006 avatar Apr 02 '24 18:04 JHDev2006

This is by design, for stability, as far as I know

See also:

  • https://github.com/godotengine/godot/issues/74941
  • https://github.com/godotengine/godot/issues/54648

AThousandShips avatar Apr 02 '24 18:04 AThousandShips

should it happen with exported dictionaries though? I get why it needs to happen for dictionaries written to files and such, but i dont see why it should need to be the same with exported dictionaries?

JHDev2006 avatar Apr 02 '24 19:04 JHDev2006

That's what exported dictionaries are though? They are stored and loaded

AThousandShips avatar Apr 02 '24 19:04 AThousandShips

but why should it be? Other than for stability as you mentioned, which seems only needed for file reading, i dont see any other reason why exported dictionaries should be sorted without the users knowledge. sort_custom should be used instead if the user or the engine REALLY has to have the dictionary sorted

JHDev2006 avatar Apr 02 '24 19:04 JHDev2006

But they are exported, so they're stored, so they're sorted

Are you printing it from the editor? Or from running project? If it's from the running project you are loading it, you have to load the scene?

AThousandShips avatar Apr 02 '24 20:04 AThousandShips

im running it from the project, but why then can it print the dictionary if its a hard coded variable, even a constant dosent have this issue, and wouldnt that be stored too?

JHDev2006 avatar Apr 02 '24 20:04 JHDev2006

Keeping insertion order is a feature according to the documentation:

Dictionaries will preserve the insertion order when adding new entries.

I don't think it should be sorted during serialization.

Dictionary keeping insertion order is a result of 4.0 changing the implementation to use HashMap instead of OrderedHashMap. But the decision of sorting keys during serialization was made way before that. So I think it's a bug.

timothyqiu avatar Apr 03 '24 01:04 timothyqiu

It also effects storing and recovering a dictionary via ConfigFile

ramdor avatar Jun 05 '24 06:06 ramdor

The cause of this issue is this line: https://github.com/godotengine/godot/blob/master/core/variant/variant_parser.cpp#L2248. I tried tracking down the original commit, but couldn't quite make it far back enough.

It definitely feels... load-bearing, but I removed it on my build a few weeks ago, and it has even fixed similar issues as well (one of my exported dictionaries kept re-sorting its keys on every resource save, which would have caused endless merge conflicts for my team).

I assume making this change would break existing test cases, but I agree that sorting dictionary keys at this stage of serialization should be considered a bug.

dog-on-moon avatar Oct 02 '24 15:10 dog-on-moon

Is there any workaround to this beyond recompiling? JSON-stringify I think loses a lot of information? I guess to use var_to_bytes, which is IIRC stable/in conformance with the documentation, but sacrificing human-readability/diffability? (I was working on an editor for my game, relying on the ordered behaviour of the Dictionaries for displaying properties in the object inspector, but the fields are shuffled about when I load them)

increpare avatar Mar 13 '25 13:03 increpare

I'm currently touching Dictionary code and want to add some points. This feature is likely to have a significant effect on performance, especially after #104047 is merged. Sorting means we need to copy the keys, sort them, and then perform hashmap lookups one by one. Without sorting, we can iterate directly over the internal HashMap with zero copies. Large Dictionarys (store in JSON or other serialization formats) are quite common in certain types of games (e.g. for storing dialogues or item data). I think it is a trade-off worth considering.

YYF233333 avatar Mar 13 '25 21:03 YYF233333

I am reluctant to deem this a "bug" given it's intentionally coded this way, but I've read enough of the above to deem this more annoying than it's worth. It's the only Variant type that does (or can do) this and it breaks user expectations.

Mickeon avatar Mar 14 '25 12:03 Mickeon

I had patched this issue locally for around 3 months and noticed no issues -- of course this is anecdotal and only covered my use cases, but it's enough for me to suggest stripping it for the 4.5 cycle, just to see if anything comes up

dog-on-moon avatar Mar 14 '25 19:03 dog-on-moon

no one has a easy way to keep dictionarys from sorting when saving a scene?

JayMikeMill avatar Mar 14 '25 21:03 JayMikeMill

I had patched this issue locally for around 3 months and noticed no issues -- of course this is anecdotal and only covered my use cases, but it's enough for me to suggest stripping it for the 4.5 cycle, just to see if anything comes up

As far as I have seen, no one has opened a PR addressing this issue yet. You could be the one.

Mickeon avatar Mar 14 '25 22:03 Mickeon

I had patched this issue locally for around 3 months and noticed no issues -- of course this is anecdotal and only covered my use cases, but it's enough for me to suggest stripping it for the 4.5 cycle, just to see if anything comes up

As far as I have seen, no one has opened a PR addressing this issue yet. You could be the one.

Okie Dokie

dog-on-moon avatar Mar 15 '25 04:03 dog-on-moon

As of Godot 4.4 with PR #77213, it is possible to manually sort when needed. In theory this means that it's not needed to do it automatically when serializing anymore, since if the user wants sorting, they can just call the function before serializing.

However, in the past, str_to_var(var_to_str(dict)) was suggested as a hack to sort Dictionaries. Making this change could break projects that expect this to work. Since sort() isn't in Godot 4.3, if PR #104164 was merged for 4.5, this would leave 4.4 as the only "transition period" version where both techniques work. I think ultimately this change is a good one, it's better to keep user data as-is when serializing, but I'm unsure about the timing of merging this.

aaronfranke avatar Mar 15 '25 07:03 aaronfranke

one of my exported dictionaries kept re-sorting its keys on every resource save, which would have caused endless merge conflicts for my team

I strongly agreed, I haven't made reproducible project or something yet, but it's definitely happend in my two machines that working my same project on editor. (Two machines are shown different order when loaded)

That's why I was keep in eyes on #104503

Creta5164 avatar Mar 23 '25 11:03 Creta5164

As of Godot 4.4 with PR #77213, it is possible to manually sort when needed. In theory this means that it's not needed to do it automatically when serializing anymore, since if the user wants sorting, they can just call the function before serializing.

However, in the past, str_to_var(var_to_str(dict)) was suggested as a hack to sort Dictionaries. Making this change could break projects that expect this to work. Since sort() isn't in Godot 4.3, if PR #104164 was merged for 4.5, this would leave 4.4 as the only "transition period" version where both techniques work. I think ultimately this change is a good one, it's better to keep user data as-is when serializing, but I'm unsure about the timing of merging this.

This is an important caveat to keep in mind indeed! Perhaps we could have a 'transition period' where we WARN_PRINT_ONCE on var_to_str(dict) if the sorted dict is different than the unsorted dict, to note that relying on auto-sort is deprecated, and will be changed in the future? This should allow everyone whom it concerns to prepare for this eventuality by adding dict.sort() manually before the call. (and everyone that doesn't care should just ignore the comment)

Ivorforce avatar May 13 '25 14:05 Ivorforce

In my 4.4/4.5-rc1 project, I was relying on Dictionary preserving insert order as stated in the docs, so the fact that serializing dictionaries does autosort was an unexpected behavior that breaks things in my project.

I ended up having to do a hack like this: config_file.set_value(section, "schema", str(schema)), since unlike var_to_str, str does preserve order, and seems to work OK in my current use-case.

I believe behavior should be consistent; when Dictionary states in the docs it preserves insert order, serialization should too. At the very least the caveat needs to be documented, so it does not come as a surprise that insert order is not actually preserved when serializing...

huyderman avatar Sep 09 '25 11:09 huyderman

When an exported dictionary is created, they keys which are set in the editor, are sorted at runtime, which is incredibly frustrating for my use case.

Can you please explain your use case?

I think it's wonderful to have dictionaries sorted alphabetically in the inspector. I think things would be much less intuitive for most users if it were random, or just stuck with whatever the actual item addition order happened to be.

Edit:

Oh, so the insert order of the dictionary is being changed, while documentation writes otherwise? I didn't realize this was supported behavior for a dictionary.

Dictionaries will preserve the insertion order when adding new entries.

My comment here is really just concerned about the Inspector's display. If this issue will remove alphabetization, then I would request that the user has some other way to organize an exported dictionary for their Inspector.

sci-comp avatar Sep 14 '25 21:09 sci-comp