# Unity [C++] Proper enum usage

## Recommended Posts

Vanderry    252
Hello GameDevs ! I really love the clear visualization of enums but I'm not entirely sure how it should be used properly. What I see is an opportunity to manage indices with easily editable text labels, so what I've done is declare enums for things like for instance in my application "error message grades".
enum ERRORGRADE
{
NONCRITICAL,	// Does not terminate the program
TERMINATE,		// Terminates the program
TERMINATEANDMSG	// Terminates the program and shows a message box
};


The declaration is stored within the header file for the CError class, and whenever I call the method Error I pass the enum element appropriate for the specific error.
void Error( std::string file, int line, ERRORGRADE grade, std::string text1 = "", std::string text2 = "" );


Now to the actual "problem". I am able to pass the elements by themselves without any hassle, but I would very much like to be explicit and pass the argument as such ERRORGRADE::NONCRITICAL to avoid passing a bad keyword (i.e. accidently using an element from a different enum). This always results in a warning in Visual Studio 2008 (warning C4482: nonstandard extension used: enum 'ERRORGRADE' used in qualified name) and it looks very bad after a whole lot of function calls. So my question is: am I using enumerators in a proper way and is there some way to call the elements through the enum scope without getting all those warnings? Many thanks in advance ! - Dave

##### Share on other sites
mattd    1078
The way you are using enums now is fine. Think of them as defining a type for which its values are from a finite set of distinct elements that are explicitly enumerated.

For your second question, enums do not have their own scope. You could put them inside another scope (like a class's), or use a namespace instead (with the side-effect of it requiring a slightly longer identifier for the type):

namespace ErrorGrade {    enum Enum {	NONCRITICAL,	// Does not terminate the program	TERMINATE,	// Terminates the program	TERMINATEANDMSG	// Terminates the program and shows a message box    };}ErrorGrade::Enum grade = ErrorGrade::TERMINATE;

##### Share on other sites
Normandy    122
I'm fairly sure this is a problem they are addressing in C++0x. Right now enums aren't even type-safe, so I presume they would add something like scope resolution for enum members.

##### Share on other sites
Washu    7829
Quote:
 Original post by NormandyI'm fairly sure this is a problem they are addressing in C++0x. Right now enums aren't even type-safe, so I presume they would add something like scope resolution for enum members.

C++0x doesn't fix the issue, it just sidesteps the issue by introducing a new type of enumeration, the "enum class" type. The enum class type is type safe, although you can use explicit casting to convert to integral type..

##### Share on other sites
Antheus    2409
Enum to int mapping is conceptually undefined, even though many languages support one way or another. Enum 'ERROR' is just that - 'ERROR'. If you choose to assign it a numeric value, the mapping is up to you. Enums conceptually also do not have relation between values. ERROR is different from WARNING, yet neither is greater as far as enums go.

Even without taking C++'s int/enum equivalence, your use of enums is not suitable for the purpose.

IMHO, the following is how the API should be used in this particular case:
void Error( std::string file, int line, std::string text1 = "", std::string text2 = "", ErrorGrade g = ErrorGrade::None );...Error("File.cpp", 17, "", "");Error("File.cpp", 17, "", ErrorGrade::Terminate);Error("File.cpp", 17, "", ErrorGrade::Terminate || ErrorGrade::MessageBox);

How the above is implemented depends. Values could be simple ints, or they could be more complex classes. The ErrorGrade above can be polymorphic as well, implementing the error behavior by itself. This design is more representative for values which can be combined (noncritical = 00, terminate = 01, terminate+box = 11, consequently just box = 10).

Alternatively, if grades are ordered, then providing a wrapper that defines order, as well as strong type safety will be better solution.

Given real world use, I'm consistently disappointed with enums and can't think of many uses for them, even in other languages. They reek too much of hardcoding. If they define functionality, then there are other ways to implement it (polymorphism, parameters). If they define data, then the data will often be best served from outside. And if for error or labeling, then const int values do the job, even if wrapped in some class.

##### Share on other sites
Decrius    100
Quote:
 Original post by AntheusAnd if for error or labeling, then const int values do the job, even if wrapped in some class.

But...an enum IS an integer! It just gives a cute name for a number. People forget numbers, names not so quickly. It's actually really handy, the enum, though its a pity that C++ seems to go so difficult about it. I have to do a lot of casting when I add an integer to an enum value. Also the way we can't define the type for the integer is a pity, as well as it's not encapsulated like a class.

I do agree that most uses of enums are best from outside, though I still prefer something that names my integers. Would be better if we could 'append' enums too, where all elements of 2 enums have unique values. In other words, make it easy for library users to extend, for example add new events. Sure, you can start from the end of the last, but what if you have 3 enums? Just getting garbage.

If 'TERMINATEANDMSG' equals 2, then why is 'TERMINATEANDMSG' - 1 not just 1 and thus 'TERMINATE'? Because it is, except that C++ wants you to add a bunch of needless castings.

##### Share on other sites
swiftcoder    18437
Quote:
 Original post by DecriusBut...an enum IS an integer!
Nope, an enum is just a name. That C/C++ choose to implement them in terms of integers is immaterial.
Quote:
 It just gives a cute name for a number.
Nope, as Antheus already mentioned, const int is how one applies a cute name to a number in C/C++.
Quote:
 ***truncated***
And those are all problems which using const int instead of enum solves in one fell swoop.

##### Share on other sites
Antheus    2409
Quote:
 Original post by DecriusIt just gives a cute name for a number. People forget numbers, names not so quickly.

As soon as you introduce ordering or treat them as ordinal types, you open a new can of bugs. Such as: ERROR + WARNING = FILE_NOT_FOUND, while WARNING * ERROR = EXIT and EXIT - FILE_NOT_FOUND + WARNING = DEFAULT.

And if treating them as bitmasks, the following problems arise:
LEFT,RIGHT,TOP,BOTTOM,LEFT_BUTTON,RIGHT_BUTTONDEVICE_OFF

Left, right, top, bottom is the direction of stick.
Buttons can be pressed at any time.
Device off means other values must be 0 or unspecified.

But this is what one uses in actual design, and enums fail to address any of those issues.

##### Share on other sites
popsoftheyear    2194
Working on reasonably old code here (15 or so years in some places), and there are many places where plain integers are passed to and returned from functions to indicate things, with a (usually) outdated, incorrect comment explaining what that value meant there. Sometimes 2 or 3 values are used for the same thing, and sometimes the same value is used more than once for different things.

Replacing those with enums (NOT const ints) has been very helpful because now when building the compiler gives me errors when just passing in integers, and some well-hidden bugs are being removed. Though not completely type-safe, just the fact that it doesn't let ints pretend to be enums (without some explicit casting), and the choices are limited to only what's valid, (and can't use cross-enums either) has been very, VERY helpful. With hundreds, maybe thousands of constant identifiers (whether #defined or const int'ed or enumed) it's also very helpful to know which set of identifiers I will be choosing from, rather than try to decypher a bunch of code and #defines which are poorly named in the first place.

These are cases where the actual value of the identifier is really irrelevant, but they just need to be unique. And we don't want to use a CompressionType where we want to know which HlsBand we are using. Are these not good candidates for enums??

##### Share on other sites
Washu    7829
Well, talking on the usage side of things:
There are almost always alternatives to the usage of named integers or enumerations.

The question becomes: Is it worth it? In the end the answer is "sometimes yes, sometimes no." More succinctly: "Maybe."

This depends heavily on your current design, on the goals of your project, on the technologies employed by your project, and many other issues as well.

The example used, which is one that deals with errors, seems a bit... wonky. I would never have an enumeration for my error severity. In fact, I'm not entirely certain what the code is trying to convey. Lets look at a few questions about the demonstration code:
Is the Error function exit-able, or does entrance to the function pose the potential to halt execution within the function?

Does the behavior of the Error function radically change depending on the parameters passed in?

Why aren't you using exceptions (and hence RAII)?

Depending on the answers to these questions your usage of an enumeration could be entirely...stupid. As an example: If the behavior of the function changes radically based on the ERRORGRADE enumeration, then you shouldn't have those behaviors all bound up in one function, but across a number of functions. If the function has the potential to exit the application without returning, then are you properly dealing with scoped objects? Less you forget: If the function never returns then some objects whose destructors would normally be called will not be. This means open files may be left dangling, sockets will abort mysteriously, and other resources you have allocated can be left in a dangling or unknown state (such as named mutexes).

Then there is the question of "Why is this in a class?" Depending on your usage of the class it may or may not be appropriate to have these functions in a class. If your simply calling these methods as single shot calls, then there's no point in using a class, free functions will be cleaner.

##### Share on other sites
Vanderry    252
Wow, thank you guys for those very interesting reflections. If I understand things correctly: it should not cause me problems to just pass one enum element as an argument in my custom functions and use for comparison with the same enum elements as long as they are within the same program on the same machine?

So far I have only checked for equivalence as such:

	if( grade == ERRORGRADE::TERMINATE )	{		PostQuitMessage( 0 );	}	else if( grade == ERRORGRADE::TERMINATEANDMSG )	{		std::string message = text1 + text2;		MessageBox( 0, message.c_str(), "Critical Error", MB_OK | MB_ICONSTOP | MB_APPLMODAL );		PostQuitMessage( 0 );	}

I like the idea of using an enum to control a switch, since it seems to accept the enum as an integral variable. Is this a situation where its usage might be considered unsafe?

##### Share on other sites
Antheus    2409
Quote:
 Original post by popsoftheyearThese are cases where the actual value of the identifier is really irrelevant, but they just need to be unique. And we don't want to use a CompressionType where we want to know which HlsBand we are using. Are these not good candidates for enums??

If you get a consensus across all developers that enums are not ints, and that there is no relation between those, unless via from_int/to_int, then they are suitable.

In practice and for historical, practical or cultural reasons, enums and ints are used interchangeably, offering no advantage.

As with everything in C++, one needs to settle on a subset of features to be productive. In case of enums, treating them as named ints is not beneficial, despite language not only allows it, but historically design was in favor of it.

Otherwise, code will rot over time, which brings us full circle. At some point, someone will simply need to use an int instead of an enum, and will force one into another.

Hence, strongly typed values are likely better, but they add complexity and verbosity. They can however result in perfectly safe code, which is still convenient to use.

It's just the age-old C++ issue, jack of all trades, master of none. It can be trained, but requires considerable upfront work on boiler-plate functionality.

##### Share on other sites
Vanderry    252
@Washu
I feel perhaps I should explain this particular implementation a bit better.

The whole application is built upon classes that return either success or failure when they are initiated, so should any call return false it will attempt to close down along the "function call branch" back into the main loop which would end seeing as a quit message was posted.

I'm sure this isn't the most fool-proof implementation, but all I really want to do with the enum is to provide myself with a lazy way of managing what each individual error call will do as I manually write the calls into the rest of the code.

I only really want critical errors at the "end" of a function call branch to display a message box, to let the user know what really caused all the trouble. The rest of the error calls should only log the error in a text file.

This probably washes out the discussion a bit but I really appreciate all of your concern :)

##### Share on other sites
cmc5788    122
Quote:
 Original post by swiftcoderNope, an enum is just a name. That C/C++ choose to implement them in terms of integers is immaterial.

This is true, but it's also silly. In my mind, the most intuitive use for something like an enum is to simply be a wrapper around such const int functionality. Enums SHOULD be the same as const ints. Conceptually, there's really no reason to ever use enums... in fact, they're kind of a trap. For what you would intuitively think they're useful for, they are actually undefined :(

##### Share on other sites
Antheus    2409
Quote:
 Original post by VanderryThe whole application is built upon classes that return either success or failure when they are initiated, so should any call return false it will attempt to close down along the "function call branch" back into the main loop which would end seeing as a quit message was posted.

This is what exceptions do.

Quote:
 I only really want critical errors at the "end" of a function call branch to display a message box, to let the user know what really caused all the trouble. The rest of the error calls should only log the error in a text file.

These are two different things, one is logging, the other are fatal errors, so they can't be handled in same way.
try {  while (...) {    // main loop stuff    log(INFO, "Hello world"); // don't quit, just log    try {      load_stuff();    } catch (file_not_found_exception & e) {      log(WARNING, "It's ok, file might not exist");    }  }} catch (std::exception & e) {  // unhandled exception, nobody caught it, we can't handle it, let's quit  PostQuitMessage( 0 );}

##### Share on other sites
cache_hit    614
Quote:
Original post by Washu
Quote:
 Original post by NormandyI'm fairly sure this is a problem they are addressing in C++0x. Right now enums aren't even type-safe, so I presume they would add something like scope resolution for enum members.

C++0x doesn't fix the issue, it just sidesteps the issue by introducing a new type of enumeration, the "enum class" type. The enum class type is type safe, although you can use explicit casting to convert to integral type..

I guess it depends what you mean by "C++0x doesn't fix the issue", but it does indeed cause the values to be scoped to the defining enum class, solving the problem the OP asked about.

##### Share on other sites
theOcelot    498
Doesn't C++0x also allow you to specify the underlying type of the enum, including allowing non-integer types?

##### Share on other sites
jwezorek    2663
Quote:
 Original post by theOcelotDoesn't C++0x also allow you to specify the underlying type of the enum, including allowing non-integer types?

I hadn't heard this. So you could define an enum as being a string?

##### Share on other sites
cache_hit    614
Quote:
Original post by jwezorek
Quote:
 Original post by theOcelotDoesn't C++0x also allow you to specify the underlying type of the enum, including allowing non-integer types?

I hadn't heard this. So you could define an enum as being a string?

It actually does still require integral types. Any integral type except wchar_t is suitable.

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf

See section 3.1 specifically.

##### Share on other sites
Vanderry    252
I must say that I'm a bit surprised so many of you oppose the use of enums when it seems so widely used, not the least in many professional DirectX-applications I have studied. I guess that might be one of those fields where their pros outweigh their cons.

##### Share on other sites
Antheus    2409
Quote:
 Original post by VanderryI must say that I'm a bit surprised so many of you oppose the use of enums when it seems so widely used, not the least in many professional DirectX-applications I have studied. I guess that might be one of those fields where their pros outweigh their cons.

I'm only opposed towards treating enums and ints as equivalent, or using them as typesafe replacement for numeric constants.

At some point, they need to be written somewhere, and then there's that old mapping problem again, and the first thing will be assuming literal int interpretation. But then this is written externally, code changes, and suddenly old values no longer make sense, yet there is no check in place, or even possible.

And not just C or C++. For example, before 1.5/5, Java lacked enum type, so a cookie-cutter version was patternized. Except that the implementation (static/singletonish-based one even) that was de-facto standard had some obscure serialization/initialization issues which would result in same enum labels having different values, sometimes even inside same VM when serialization was involved.

IMHO - either full static type safety, or full dynamic language. The things in between tend to annoying in the long term, even if over short-term a tool, perhaps an inference type analyzer can help a bit.

This is especially true for C++ under modern compilers which are good at eliminating unused code, or minimizing memory layout of such convenience wrappers.

While likely overbloated and over-engineered, perhaps look at boost::error's design.

## Create an account

Register a new account

• ## Partner Spotlight

• ### Similar Content

• Hello! I am building the main scene in Unity for a 3D cards game. My goal is creating "card slots" to place the different cards from a deck and use it as "buttons". The image below represents somehow what I want to develop. I have been reading and I think that I have to generate a canvas and place in my scene the slots where I want to place the cards, but I am not sure about it. Also, to use the cards, I don't know if setting buttons is the best option (maybe I should use images instead).
All recommendations and tips are welcome

• Hi! We are looking for a unity 3D developer to join our small "beginners" team. We are 3 artists (illustration, concept and 3D modeling), 2 designers and 1 programmer (me). We are developing an online video game that we have already designed. Our goal is to create a small studio and build up this game to take it to video game events around Europe and try to find publishers. Also we want to learn step by step how to develop games, so, is better if you don't have a huge experience in developing
For more information, or any question, you can send us an email to cursetalegame@gmail.com
Cheers

• The legendary UAZ SUV is off in an unprecedented expedition on the picturesque,
yet rugged regions of Russia. Powerful domestic cross-country vehicles have to go through many trials in the expanses of the country! There are three game modes (Exploring the world, Delivery and Checkpoints).
Explore the vastness of Russia, perform tasks, and feel the power of the legendary UAZ!

Features:
- Large Map.
- Diverse terrain (mountains, villages, fields, etc.)
- Modern graphics and effects.
- Pleasant music.
- 11 types of camera views.
- Different weather conditions (fog, rain, etc.)
- Game modes (Free Driving, Delivery & Checkpoints)
- 3 models of the legendary brand.
- And much more!

• Arcade game in black and white style. In it you will need to drive a motorcycle through a variety of challenging trails. Come accessible trails and open new ones. All in the game of their 21 game features realistic physics, and you will need to acquire the skill that would deal with it.