% Enums
%
%

Enums: Motivation
=================

We have seen that case classes *aggregate several values* into a single abstraction.
For instance, the `Rational` case class aggregates a numerator and a denominator.

Conversely, how could we define an abstraction *accepting alternative values*?

\example

Define a `Paradigm` type that can be either `Functional` or `Imperative`.

Enums
=====

We can define an abstraction accepting alternative values with an \red{enum}:

~~~
enum Paradigm
  case Functional, Imperative
~~~

This definition introduces:

- A new \red{type}, named `Paradigm`.
- Two possible \red{values} for this type, `Paradigm.Functional` and
  `Paradigm.Imperative`.

Enumerate the Values of an Enumeration
======================================

It is possible to enumerate all the values of an enum by calling the
`values` operation on the enum companion object:

\begin{tabular}{ll}
 \verb@Paradigm.values@              \wsf Array(Functional, Imperative) \\
 \verb@val p = Paradigm.Functional@  \wsf p: Paradigm = Functional \\
 \verb@p == Paradigm.values(0)@      \wsf true
\end{tabular}

Discriminate the Values of an Enumeration
=========================================

You can discriminate between the values of an enum by using a \red{match}
expression:

~~~
def isReferentiallyTransparent(paradigm: Paradigm): Boolean =
  paradigm match
    case Paradigm.Functional => true
    case Paradigm.Imperative => false
~~~

->

And then:

\begin{tabular}{ll}
 \verb@val p = Paradigm.Functional@   \wsf p: Paradigm = Functional \\
 \verb@isReferentiallyTransparent(p)@ \wsf true
\end{tabular}

Match Syntax
============

_Pattern matching_ is a generalization of `switch` from C/Java
to class hierarchies.

It’s expressed in Scala using the `match` keyword.

- `match` is followed by a sequence of \red{cases}, `case value => expr`.
- Each case associates an \red{expression} `expr` with a
  \red{constant} `value`.

We will see in the next slides that pattern matching can do more
than discriminating enums.

Enumerations Can Have Methods
=============================

Alternatively, we can define `isReferentiallyTransparent` as a method:

~~~
enum Paradigm
  case Functional, Imperative

  def isReferentiallyTransparent: Boolean = this match
    case Functional => true
    case Imperative => false
~~~

->

And then:

\begin{tabular}{ll}
 \verb@val p = Paradigm.Functional@  \wsf p: Paradigm = Functional \\
 \verb@p.isReferentiallyTransparent@ \wsf true
\end{tabular}

Enumerations Values Can Take Parameters
=======================================

Consider the following definition of a data type modeling students
following a lecture:

~~~
enum Student
  case Listening
  case Asking(question: String)
~~~

This definition introduces a `Student` type consisting of two cases,
`Listening` or `Asking`. The `Asking` case is parameterized with a
value parameter `question`. Since `Listening` is not parameterized,
it is treated as a normal enum value.

Matching on Constructors
========================

Since `Asking` is not a constant, we match on it using
a _constructor pattern_:

~~~
student match
  case Student.Listening => "Student is listening"
  case Student.Asking(q) => s"Student is asking: $q"
~~~

A constructor pattern allows us to _extract_ the value of
the `question` parameter, in case the `student` value is
indeed of type `Asking`.

Here, the `q` identifier is bound to the `question` parameter
of the `student` object.

Evaluating Match Expressions
============================

An expression of the form
$$\btt
e\ match\ \{\ case\ p_1 => e_1\ ...\ case\ p_n => e_n\ \}
$$
matches the value of the selector $\btt e$ with the patterns
$\btt p_1, ..., p_n$ in the order in which they are written.

The whole match expression is rewritten to the right-hand side of the first
case where the pattern matches the selector $e$.

References to pattern variables are replaced by the corresponding
parts in the selector.

Forms of Patterns
=================

Patterns are constructed from:

 -  _constructors_, e.g. `Rational`, `Student.Asking`,
 -  _variables_, e.g. `n`, `e1`, `e2`,
 -  _wildcard patterns_ `_`,
 -  _constants_, e.g. `1`, `true`, `Paradigm.Functional`.

Variables always begin with a _lowercase letter_.

The same variable name can only appear _once_ in a pattern.

Names of constants begin with a capital letter,
with the exception of the reserved words `null`, `true`,
`false`.

What Do Patterns Match?
=======================

- A constructor pattern $\btt C(p_1 , ..., p_n)$ matches
  all the values of type $\btt C$ (or a subtype) that have been
  constructed with arguments matching the patterns $\btt p_1, ..., p_n$.
- A variable pattern $\btt x$ matches any value, and
  \red{binds} the name of the variable to this value.
- A constant pattern $\btt c$ matches values that are equal to
  $\btt c$ (in the sense of `==`)

Matching on Case Classes
========================

Constructor patterns also works with case classes:

~~~
def invert(x: Rational): Rational =
  x match
    case Rational(0, _) => sys.error("Unable to invert zero")
    case Rational(n, d) => Rational(d, n)
~~~

Relationship Between Case Classes and Parameterized Enum Cases
==============================================================

Case classes and parameterized enum cases are very similar.

When should you use one or the other?

- Parameterized enum cases should be used to define a type
  that is part of a set of alternatives,
- If there are no alternatives, just use a case class.

Enumerations Can Be Recursive
=============================

A list of integer values can be modeled as either an empty list,
or a node containing both a number and a reference to the remainder
of the list.

~~~
enum List
  case Empty
  case Node(value: Int, next: List)
~~~

A list with values `1`, `2`, and `3` can be constructed as follows:

~~~
List.Node(1, List.Node(2, List.Node(3, List.Empty)))
~~~

Enumerations Can Take Parameters
================================

~~~
enum Vehicle(val numberOfWheels: Int)
  case Unicycle extends Vehicle(1)
  case Bicycle  extends Vehicle(2)
  case Car      extends Vehicle(4)
~~~

- Enumeration cases have to use an explicit `extends` clause

Exercise: Arithmetic Expressions
================================

Define a datatype modeling arithmetic expressions.

An expression can be:

- a number (e.g. `42`),
- a sum of two expressions,
- or, the product of two expressions.

`Expr` Type Definition
======================

~~~
enum Expr
  case Number(n: Int)
  case Sum(lhs: Expr, rhs: Expr)
  case Prod(lhs: Expr, rhs: Expr)

->

\begin{tabular}{ll}
 \verb@val one = Expr.Number(1)@  \wsf one: Expr = Number(1) \\
 \verb@val two = Expr.Number(2)@  \wsf two: Expr = Number(2) \\
 \verb@Expr.Sum(one, two)@        \wsf Sum(Number(1), Number(2))
\end{tabular}


Exercise
========

Is the following match expression valid?

~~~
expr match
  case Expr.Sum(x, x) => Expr.Prod(2, x)
  case e              => e
~~~

     O         Yes
     O         No

Exercise
========

Implement an `eval` operation that takes an `Expr` as parameter and
evaluates its value:

~~~
def eval(e: Expr): Int
~~~

Examples of use:

\begin{tabular}{ll}
 \verb@eval(Expr.Number(42))@  \wsf 42 \\
 \verb@eval(Expr.Prod(2, Expr.Sum(Expr.Number(8), Expr.Number(13))))@  \wsf 42
\end{tabular}

Exercise
========

Implement a `show` operation that takes an `Expr` as parameter and
returns a `String` representation of the operation.

Be careful to introduce parenthesis when necessary!

~~~
def show(e: Expr): String
~~~

Examples of use:

\begin{tabular}{ll}
 \verb@show(Expr.Number(42))@  \wsf "42" \\
 \verb@show(Expr.Prod(2, Expr.Sum(Expr.Number(8), Expr.Number(13))))@  \wsf "2 * (8 + 13)"
\end{tabular}

Summary
=======

In this lecture, we have seen:

- how to define data types accepting alternative values using
  `enum` definitions,
- enumeration cases can be discriminated using pattern matching,
- enumeration cases can take parameters or be simple values,
- pattern matching allows us to extract information carried by an object.