In this section you will learn about enums, which are convenient way to construct data composed from cases. In the previous session, you've learned how to model data with class hierarchies. Classes are essentially bundles of functions that operate on some common values that are represented as fields. They are very useful abstraction, since they allow encapsulation of data. But sometimes we just need to compose and decompose pure data without any associated functions. Case classes and pattern matching work very well for this task. Here's our case class hierarchy for expressions, again. We have the base trait expression, and then we have four case classes for variables, numbers, sums, and products that all extend expressions. This time we've put all case classes in the expression companion object in order not to pollute the global namespace. Here it's expression dot number 1 instead of just number 1 for example. That means the type number of R couldn't accidentally clash with something of the same name that we have defined on the outside. Of course, one can still pull out all the cases using an import. You can write import Expression._ that would pull out everything that's defined in object expression and make it available in the global namespace. Note that there are no methods in these definitions. All we've done is define some base trait and case classes that extend the base trait and thus defined in particular cases how data of the case trait can be constructed and pattern matched upon. Pure data definitions like these are called algebraic data types or ADTs for short. ADTs are quite pervasive in functional programming. To make them even more convenient, scatter offers some special syntax. What you can do alternatively is use an enum to define an ADT. An enum enumerates all the cases of an ADT and nothing else. The way to do it here would be to write enum expression instead of the base trait. Then simply the cases var number some Prod inside. That enum is equivalent to the case class hierarchy of the previous slide, but it's shorter since it avoids the repetitive class Prod extends expression notation. That was the case class hierarchy, and that's the equivalent enum. Since enums are just shorthands for case class hierarchies, we can use match expressions on them as usual. For instance, to print expression with proper parameterizations, we could use this show method here. The other implementation is like the one we did in the exercise two sessions ago. The only difference is that now since the case classes are inside the expression object, I have to prefix them with expression dot, as you see here. Of course, I could also import the expression object like this and then I could use the normal patterns which you see here in the showP method, where we used sum without an expression prefix. Even simpler enums. The cases of an enum can also be simple values, so no case classes just constants, in which case I wouldn't have any parameters. For instance, we can define a color type with values red, green, and blue like this, enum color, case red case, green case blue, or even shorter, we can put the three cases on a single line. Enum color, case red, green, blue would give us a simple color type. For pattern matching, this simple cases count as constants. For instance, I could define an enum day of week with the seven days. I can import it and then I could have a function isWeekend that says takes a day and matches the day if it's a Saturday or a Sunday it returns true, and otherwise it returns false. Here are some more refinements of enums. Enumerations can also take a parameters and they can define methods. Here we have an enum direction that has two parameters which have happened to be val parameters dx and dy. So that's the displacement in the x coordinate and the y coordinate. Right would be the direction 1, 0, that's x, that's y. Up would be 0, 1, left would be -1, 0, and down would be 0 ,-1. The other thing we define here is the method leftTurn, which is a method defined on enums of this direction type. The way we do it is that we make use of two auxiliary functions, ordinal and values. Ordinal is the ordinal number of an enum value that's essentially just a number that starts with 0 and goes up one for per case that we have defined. What we do here is we take the ordinal number plus 1, so the next one, modulo 442. We have a wrap around and go from down to right, and that gives us an integer number and then we can make use of the second method which is called values. Values takes an int and gives us the enum that has the ordinal number that's given as the end. In this case leftTurn would be Direction.values of ordinal plus 1 modulo 4. Let's say we start with direction right, and we want to do a left turn on that. Right as the ordinal number 0, so if the next ordinal number that we compute here is 1 and the direction values of 1 would be up. So we get up as the result of leftTurn on right. Then if you want to get the fields of the up value, so dx would be 0 and the dy would be 1. Here some further explanations for this example. Cases that pass parameters to the enclosing enum always use an extends class, so it's extends Direction and then that's followed by the actual arguments for those parameters. Expression e.ordinal gives the ordinal value of the enum case E. Cases start with 0 and are numbered consecutively. Values is an immutable array and the companion object of an enum that contains ordinal values. Furthermore, only simpler cases have ordinal numbers and show up in values. Parameterized cases do not, because there's not a single value that represents a parameterized case. You've seen that ADT enums are shorthands for class hierarchies with case classes. Similarly, enums with simpler cases are shorthands for classes and simple values. The direction enum that we've seen is expanded by the Scala compiler to roughly the following structure that you see here. We have a base class direction that takes the parameters as given. We would see a left turn here as the method and then in the companion object of direction, we would have the four cases, which in this case are all individual values, right, up, left, and down. Each value is an instance of an anonymous subclass of class direction with the proper values for the parameters. Then of course there are also the compiler defined helper methods ordinal in each case and values and there's another method value of the companion object, value off. Let's look at the enum case that corresponds to a string which is the name of the case. ADTs and enums are quite common in more applied functional programs where the task is often to model some domain, so in that case, when often needs to define a large number of data types without having to attach any operations. As a small example of this, let's say we want to model payment methods, that could be an enum payment method where we could say, well, one payment method would be by credit card. Which case we want to know the kind, so what card it is? Who's the holder? What's the number of the card and what's the expiry date? Or a payment method could be PayPal, in which case we would want the e-mail or a payment method could be cash. The most concise ways to write these things down is as an enum in the way you've seen here. Or here's a simple enum for credit cards where we just say a credit card is Visa MasterCard, or Amex. To summarize, in this unit, we've covered two uses of enum definitions. First, as a shorthand for hierarchies of case classes, in which case we talk about an ADT typically. Second is a way to define data types that accept alternative values similar to enums in many other languages. The two cases can be combined in Scala and enum can comprise parameterized and simpler cases at the same time. We've seen an example in payment method where a payment method has two parameterized cases here, credit card and PayPal, and a simple case, cash. Enums are typically used for pure data, where all operations on such data are defined elsewhere.