Enum as key in a Dictionary

Godot Version

godot-4

Question

I am trying to use enum as Configuration key and I want to store the matching value into a Dictionary. A key-value store of configurations, with static names.

The problem I am facing is that the parser complains the format of the key.

res://Game/Singletons/UIConfiguration.gd:11 - Parse Error: Expected identifier or string as Lua-style dictionary key (e.g “{ key = value }”).

(line 11 is the first initialization)

extends Node
class_name UIConfiguration

enum ConfigurationKey {
	Progress_bar_height,
	Progress_bar_width
}
	
var _IntConfigurationValues : Dictionary[ConfigurationKey, int] = {
	ConfigurationKey.Progress_bar_height = 48,
	ConfigurationKey.ConfigurationKey.Progress_bar_width = 320
}

If is use another form

var _IntConfigurationValues : Dictionary[ConfigurationKey, int] = {
	Progress_bar_height = 48,
	ConfigurationKey.Progress_bar_width = 320
}

Then I face the runtime error:
E 0:00:00:217 UIConfiguration.gd:10 @ @implicit_new(): Unable to convert key from “StringName” to “int”.
<C++ Error> Method/function failed.
<C++ Source> core/variant/dictionary.cpp:478 @ assign()
UIConfiguration.gd:10 @ @implicit_new()

Question

what is the correct form to initialise with Enum?

1 Like

You need to wrap your key = value in {} brackets.


extends Node
class_name UIConfiguration

enum ConfigurationKey {
	Progress_bar_height,
	Progress_bar_width
}
	
var _IntConfigurationValues : Dictionary[ConfigurationKey, int] = {
	{ConfigurationKey.Progress_bar_height = 48},
	{ConfigurationKey.Progress_bar_width = 320}
}

See the docs

2 Likes

You can also use an Array and just use the Enum values as the index. Each Enum values by default gets an int equivalent starting at 0.

Use the colon to build dictionary key value pairs.

var _IntConfigurationValues : Dictionary[ConfigurationKey, int] = {
	ConfigurationKey.Progress_bar_height:48,
	ConfigurationKey.Progress_bar_width:320
}
2 Likes

Seems a bit pointless given that an Enum is a ‘set’ of values with a number that can be arbitrarily set anyway.

Why not just do this:

enum ConfigurationKey {
	Progress_bar_height = 48,
	Progress_bar_width = 320
}

And then just get cast to the int of the enum value. (which I assume you can do in GD Script)

Or not …

Thats a pretty big oversight if you cant do that.

2 Likes

I thought Godot wouldn’t allow to assign 2 different keys to the same value, but apparently that’s not a problem and this works just as good:

enum ConfigurationKey {
	Progress_bar_height = 48,
	Progress_bar_width = 48,
}

So yeah, the whole Dictionary is obsolete and you can just use the enum directly. Unless you want to be able to change the values at some point, then you need a Dictionary, because enums are immutable.

I tested and it’s not a problem anymore, there is no error, you can do all operations and casting directly on the enum.

1 Like

Technically the name element of the enum is its key, not its constant numeric value.

So

enum ConfigurationKey {
	Progress_bar_height = 48,
	Progress_bar_width = 48,
}

In reality (at compile time) is just

0,48
1,48

1 Like

True, it’s pretty well defined in the docs and it even says that specifically.

Multiple keys with the same value are allowed.

Enum is basically a wrapper for a Dictionary.
Cool, learnt something new :wink:

2 Likes

An Enum is constant. From context I assume that the values are configuration values read from a file. So you can’t put the values in the Enum declaration because they are going to change.

TBH I don’t know why OP is trying to do that to begin with. It was late and I was just throwing the idea against the wall to see what sticks.

I’ve tried to tie a number of things to Enums in Godot over the years, and personally I’ve often found that it’s a step to a different solution that I think about while I’m trying to implement my Enums or after using them a while.

1 Like

Thanks @sancho2, it works.

1 Like

This approach, wrapping key = value in parenthesis, leads to static error message. I tried with wrapping with colon {key:value} and it does not work.

var _IntConfigurationValues : Dictionary[ConfigurationKey, int] = {
	{ConfigurationKey.Progress_bar_height = 64},
	{ConfigurationKey.Progress_bar_width = 320}
}

Line 19:Expected identifier or string as Lua-style dictionary key (e.g “{ key = value }”).

var _IntConfigurationValues : Dictionary[ConfigurationKey, int] = {
	{ConfigurationKey.Progress_bar_height : 64},
	{ConfigurationKey.Progress_bar_width : 320}
}

Line 19:Expected “:” or “=” after dictionary key.

Tested in Godot 4.5 beta 5 and 4.4.1 without success.
Is it a regression ?

For some reason I assumed you worked with C# and suggested you a C# syntax.
I think all those {} brackets messed with my brain :slight_smile:
In GDScript, the correct syntax is as mentioned by @sancho2

1 Like

An Enum in the end is a static array where nothing changes, it cant be changed, ever, and the labels are changed to the underlying integer when compiled. They are really only there to make code more readable. If you could then you would destroy the point of them in the first place.

For example (and this is a real world one from a project I am currently working on). Lets say you wanted to ensure that certain node2d layers had correct z ordering. Of course you could do that just by setting them in the scene and thats fine.

But lets say for some reason at some point in the game you wanted to shift those layers around, so you need to change the z ordering in code.

You could of course just change the Zindex to whichever number you wanted, but you could also do something like this: (in C#)
(These are not necessarily the numbers I am currently using , just an example)

    public enum ZOrdering
    {
        ONTOP = 4000,
        PLAYAREA = 0,
        TILEMAP = -5,
        BEHINDPLAYAREA = -10,
        BACKGROUND = -20
    }

And then to use those you could do something like this: (The Enums are in an autoload to make them global)

ZIndex = (int)Enums.ZOrdering.ONTOP;

Nice readable code, the cast is getting the assigned value, the underlying number of each entry in the Enum is compiled at runtime.

I’m just not sure what the OP is trying to achieve as you can just do this already with the Enum itself. Assuming its static information, which given the class name is UIConfiguration, suggests it would be.

You could of course just use a Vector2 as well in the end.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.