Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

Enumerations1 are often associated with procedural code rather than object-oriented code. They tend to give rise to similar switch statements scattered through the code, and in general, these are replaced by polymorphism in object-oriented code.

For example, see Replace Type Code with Class, Replace Type Code with Subclasses, and Replace Type Code with State/Strategy in Refactoring by Martin Fowler. Closely related, see Replace Conditional With Polymorphism in the same volume; Bob Martin also has quite a bit to say on the disadvantages of switch statements in Clean Code (for example, heuristic G23 Prefer Polymorphism to If/Else or Switch/Case).

However, since object-orientation, like any other good paradigm, can be a powerful tool but is not a silver bullet, are there times when using an enumeration is a good decision?


1I use this term broadly; not just for something which is strictly an enum in a C-based language, but for any set of entities that are used to represent it (a class with a set of static members, etc...).

share|improve this question
2  
hmmmm....this is the first time I've heard enumerations are bad. I guess error-prone strings or magic numbers must be better? –  Dunk Sep 17 '13 at 22:09
2  
@Dunk You will note that I carefully avoided saying enumerations are bad. I merely stated that they are more closely associated with procedural than object-oriented code, in general. –  Kazark Sep 17 '13 at 22:35
1  
"Enumerations1 are typically associated with procedural code rather than object-oriented code." - this is nonsense for a start. Who told you this? –  James Sep 18 '13 at 9:35
1  
I tend to use enums for properties in objects that can take one of many different values. For instance, if I'm writing a packet parser, I'd want to know whether the packet was RX'd or TX'd, so I'll have a direction enum rather than (as @Dunk pointed out) magic numbers of error prone strings. –  Jamie Taylor Sep 18 '13 at 10:24
1  
It is interesting to note that, when Nicklaus Wirth tackled object-oriented programming, in his Oberon language, enumerations were one of the things he dropped from the language, because he couldn't find an acceptable way to allow "derived objects" to extend the enumeration. –  John R. Strohm Sep 18 '13 at 12:40

5 Answers 5

PEP 435 was the proposal to add enumerations to Python. The motivation for adding enumerations:

The properties of an enumeration are useful for defining an immutable, related set of constant values that may or may not have a semantic meaning. Classic examples are days of the week (Sunday through Saturday) and school assessment grades ('A' through 'D', and 'F'). Other examples include error status values and states within a defined process.

Enumerations serve the same purpose in object-oriented code as in procedural code.

share|improve this answer

As you said, enumerations tend to give rise to case discrimination … after all, how else are you going to make sense of the different values of the enumeration?

But in OOP, we already have a perfectly good way of doing case discrimination: polymorphic message dispatch. That's all you need. You don't need case or switch or even if or for or while. Smalltalk doesn't have any of those, it doesn't have any conditionals, it doesn't have any loops, it doesn't have any case discrimination. Only polymorphic message dispatch. And it works just fine that way.

So, where you would do something like this in a language without polymorphic message dispatch:

enum Weekday {
  Monday, 
  Tuesday, 
  Wednesday, 
  Thursday, 
  Friday, 
  Saturday, 
  Sunday
}

def weekdayToString(day: Weekday) = match day {
  case Weekday.Monday    => "Monday"
  case Weekday.Tuesday   => "Tuesday"
  case Weekday.Wednesday => "Wednesday"
  case Weekday.Thursday  => "Thursday"
  case Weekday.Friday    => "Friday"
  case Weekday.Saturday  => "Saturday"
  case Weekday.Sunday    => "Sunday"
}

def printWeekday(day: Weekday) = println(weekdayToString(day))

printWeekday(Weekday.Wednesday)
// Wednesday

In a language with polymorphic message dispatch, you would do it like this:

sealed trait Weekday
object Monday    extends Weekday { override def toString() = "Monday"    }
object Tuesday   extends Weekday { override def toString() = "Tuesday"   }
object Wednesday extends Weekday { override def toString() = "Wednesday" }
object Thursday  extends Weekday { override def toString() = "Thursday"  }
object Friday    extends Weekday { override def toString() = "Friday"    }
object Saturday  extends Weekday { override def toString() = "Saturday"  }
object Sunday    extends Weekday { override def toString() = "Sunday"    }

def printWeekday(day: Weekday) = println(day)

printWeekday(Wednesday)
// Wednesday

(That is actually runnable Scala code.)

In other words: you can always replace an enumeration with case discrimination with an inheritance hierarchy with polymorphism.

Interestingly, Scala actually does have enumerations, but there are efforts for removing them from the language. They just don't add any significant expressive power to a language which already has objects.

share|improve this answer
1  
Jörg, I feel like your example is flawed. In Scala a sealed trait basically corresponds to a Java enum (which can also have behaviour). So it is nice that you can do that in Scala - but sealed trait is imho just another word for a java enum - what do you think? –  Falcon Sep 18 '13 at 11:50
    
I have to agree with @Falcon. In fact, it's possible to write idiomatic Java code that looks a lot like those sealed traits... only using Enums and overriding toString(), much like you did. No need to use switch with enums, either! If you must use switch, Enums in Java help with pseudo-"pattern matching": the compiler will warn you if you are missing "patterns". –  Andres F. Sep 18 '13 at 14:09
    
+ You can iterate over enums whereas it's a bit harder and noisier to do the same thing with traits –  Falcon Sep 18 '13 at 14:15

Enums have basically two purposes:

  1. They help you enforce type safety
  2. They can act as a container for mutually-exclusive constants

Given those purposes, of what use are enums, even in object oriented languages?

In my opinion coding is all about finding the right way to express something in a specified context.

Often you don't have the need for a fully blown class. You don't introduce a class if you need to encapsulate constant, static data without or with only minimal behaviour. An enum is a better way to express your semantical needs rather than to derive it from the type of subclass, which is pretty much the only alternative involving polymorphism (and leads to switch statements on the types of subclasses as well).

Further, you keep control over the available values all the time. You cannot just put good old Liskov to use and sneak in another subclass with new behaviour. In some scenarios, that's a very much desired behaviour. One should also note that in some languages like Java enums can carry behaviour. So they can bring the behaviour you want right to the place you want it to be. As Jon Skeet put it:

An enum in Java is a fixed set of objects, basically. The benefit is that you know that if you have a reference of that type, it's always either null or one of the well-known set.

Practically speaking, in most cases where you'd just return arbitrary well-defined values (like error codes) you should switch to an enum to enforce type safety. This way you limit the amount of failure that is introduced by returning a wrong value by accident as the compiler can check it. Especially if there's little need for behaviour and the associated data is static.

share|improve this answer
    
I'll note that "mutually exclusive" is generally not a requirement for enums, which can also be defined as bitfields in order to support multiple values. –  Aaronaught Sep 18 '13 at 0:18
    
Constants are only "mutually exclusive" in that each needs to be unique. They can be combined very well into "sets of enum values". IE repeated calendar item occuring on every second tuesday and wednesday, would probably use a set of weekday (where weekday is the enum) for the (week)days on which the calendar item occurs. –  Marjan Venema Sep 18 '13 at 10:09
    
Imho enum values that are combined inherently into a bitset are impure and this feature should not be called enum anymore, but a bitset in which each bit represents something. The bits themselves can be enumerated. I know some C languages allow that and personally I don't like it. –  Falcon Sep 18 '13 at 11:41

. . . are there times when using an enumeration is a good decision?

I used an enum (via C#) to define a fixed, ordered set of "tasks". The underlying integer values defined order. A wrapping class used the enum for instance equality. A collection class used the enum for sorting and enforcing uniqueness w/in the collection. These classes replaced code that was hopelessly broken functionally and conceptually.

That enum was effectively a "core" data structure at the heart of higher-functioning composite data structures. In capturing essence of the domain objects at the core the composites were clean and the business functionality was delightfully concise.

share|improve this answer

Yes, there are valid uses of enumerations, even in systems which are primarily object-oriented.

In a layered architecture, an enumeration can be valuable in keeping. the separation of concerns between layers or modules. For example, a lexer and a parser may talk to each other in tokens, would could be some sort of enumeration.

Similarly, in a service-oriented architecture, when there is a reason for some sort of type code to cross multiple services and this cannot accomplished with multiple events instead, there may be good reason to use an enumeration.

On a little different note, it may be a useful temporary measure in emergent design in which you are waiting to make sure you get the abstract right before moving to a polymorphic solution.

But still, use enumerations with care.

share|improve this answer
1  
@Falcon perfectly valid and encouraged. There's even a badge for it. See What is this “answer your own question” jazz? from MSO about it. –  MichaelT Sep 17 '13 at 21:38
3  
@Falcon: I quote this blog post: "To be crystal clear, it is not merely OK to ask and answer your own question, it is explicitly encouraged." –  Kazark Sep 17 '13 at 21:39
3  
@Falcon If you do it for reputation - that's bad. -- Says who? It's OK to pimp rep if you're answering someone else's questions, but not your own? –  Robert Harvey Sep 17 '13 at 21:59
2  
That said, the answer is not all that great. It basically says "Sometimes they're good, but sometimes they're not." It doesn't really explain in detail the contexts under which an enumeration could be good or bad. –  Robert Harvey Sep 17 '13 at 22:01
1  
@RobertHarvey: To be fair, I don't think it's a particularly good question, seeing as how there's no elaboration whatsoever on why enums in OOP would be any different from enums in any other model (procedural, functional, and so on). The question could easily be changed to "when should I use enums, period?" and that might rightly be closed as too broad. –  Aaronaught Sep 18 '13 at 0:21

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.