Bitmask / Bitshifting for Enums represented in SelectionGrid

This is really a sanity check as I have no other engineers on my job to run this by.

I have an enum called Languages, the members of which I’ve assigned power of two integers:

public enum Languages
{
    English = 1,
    Arabic = 2,
    Klingon = 4,
    Jibberish = 8,
};

I am displaying these in a SelectionGrid in OnGUI using the technique:

_selectedLanguage = GUI.SelectionGrid (new Rect (100f, 0f, 100f, Screen.height * .12f), _selectedLanguage, _languageNames, 1);

Where _languageNames is {“English”,“Arabic”,“Klingon”,“Jibberish”}, extracted from the Languages enum (not hard coded, of course!)

The user selects a language in the UI, and I want to store it in playerprefs. I’m taking advantage of the fact that I’m using power of two’s in my enum to use bit-shifting to extract the Language selected using the zero-based selected index stored in _selectedLanguage:

string lang = ((Languages)(1 << _selectedLanguage)).ToString();
PlayerPrefs.SetString("Language", lang);

This works but it seems hacky. Is there a better technique I’m missing?

Is there any reason you’re assigning them as powers of 2, other than for this SelecitonGrid?

I ask because SelectionGrid only allows selecting one entry of the many. Not multiple. But power of 2 enum values are usually used only for those enums that are flagging (you can construct a bitmask of the enum values representing, in your case, the ability to speak more than 1 language, and what languages they are).

If they’re supposed to be flagging enum values, I suggest attributing your enum as ‘Flags’:

[System.Flags]
public enum Languages
{
    English = 1,
    Arabic = 2,
    Klingon = 4,
    Jibberish = 8
}

So:

var spokenLanguages = Languages.English | Languages.Jibberish;

if (spokenLanguages & Languages.Jibbers != 0)
{
    //do something if speaks Jibberish
}

If the languages shouldn’t be flagging, then it’s kind of superfluous.

Now, as for your way of dealing with it, I personally would suggest against it. The code is very adhoc and specific to your case. This can result to easy breaking on maintenance of the code.

You have an array of the names of the enum values ‘_languageNames’. You had to construct this array. How did you construct the array? Is it just a static array? Well… make a 1 to 1 array of the related enum values for each. You could even have a dictionary linking the two.

If you made the array by ‘ToString’ each possible enum value. Well… System.Enum actually has a way to parse that string name back into the enum value itself:

Note it works for strings of either the numeric OR the name of the enum value.

I’d go with either of these routes because it doesn’t depend on the numeric structure of the values. You could use it with enums that are linear (1,2,3,4,5…), flagging (1,2,4,8,16…), or random (-1,0,1,5,9…).

You can also generalize it into a function that can handle any enum. You just pass in the enum value and the function figures out the available options based on that.

This is how EditorGUILayout.EnumPopup works (using the parsing) :