You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
This repository was archived by the owner on Mar 27, 2025. It is now read-only.
Their implementation is awkward for even simple use-cases such as defining a finite number of user-defined elements
Scala 3 adds the new and versatile enum construct which is syntactic sugar
The design of enum meets the following objectives:
Allow for a concise expression and efficient definition of enumerations
Allow the modelling of Java enumerations as Scala enumerations
Allow for a concise expression of ADTs
Support of all idioms expressible with case classes
Let's have a short look at each of them
enum - Encoding values - I
Encoding of a series of values is simple:
enumColor:caseRed, Green, Blue
And using them
valred=Color.Red
println(s"""Ordinal of Red = ${red.ordinal}""")
// Get all values in enumerationvalenums:Array[Color] =Color.values
println(s"Values in enumeration Color: ${enums.mkString("Array(", ", ", ")")}")
// Access a value by its namevalblue=Color.valueOf("Blue")
println(s"""Ordinal of Blue = ${blue.ordinal}""")
Which will print:
Ordinal of Red=0Values in enumeration Color:Array(Red, Green, Blue)
Ordinal of Blue=2
objectPlanets:importPlanet.*valearthWeight=1.0valmass= earthWeight /Earth.surfaceGravity
valweightOnPlanets=for p <- values yield (p, p.surfaceWeight(mass))
Modelling of Java enumerations as Scala enumerations
Achieved by extending java.lang.Enum
scala>enumColorextends java.lang.Enum[Color]:caseRed, Green, Blue// defined class Color
scala>Color.Green.compareTo(Color.Green)
valres0:Int=0
scala>Color.Green.compareTo(Color.Blue)
valres1:Int=-1
Representing ADTs using enum
scala>enumMyOption[+T] {
caseMySome(x: T)
caseMyNone
}
// defined class MyOption
scala>importMyOption._
scala>valoInt=MySome(12)
valoInt:MyOption[Int] =MySome(12)
scala>valoNone=MyNonevaloNone:MyOption[Nothing] =MyNone
scala>valoInt:MyOption[Nothing] =MyNonevaloInt:MyOption[Int] =MyNone
Note that MyNone is inferred as MyOption[Nothing]
As any enum, ADTs can have fields
Application of enum for protocol definitions
Instead of using the Scala 2 way of defining an Actor's protocol with sealed traits, we can use enums
The above enum is de-sugared into case classes and values
There is one issue: we have to refer to enum members using a qualification
someActor !SomeActor.Command.Execute(5)
We can solve this using Scala 3's export feature
enum internals - I
The different cases on an enum are defined in the enum's companion object
The underlying case classes are not visible in the return type of the apply methods used to create them
They can be made visible by constructing them with a new
The default behaviour
scala>enumCommand:caseResetcaseIncrementBy(inc: Int)
caseConfigure(init: Int, inc: Int)
scala>valreset=Command.Reset// `reset` is a singleton case mapped to a val definition valinc=Command.IncrementBy(2) // `inc` is NOT a case classvalr1=Command.Resetvalr2=Command.Reset
scala> println(r1 eq r2)
true
scala> inc.<TAB> // which members are defined on this enum instance?-> ne equals $ordinal getClass formatted isInstanceOf!=== wait notify ensuring hashCode notifyAll synchronized## eq clone ordinal finalize toString asInstanceOf
enum internals - II
Making underlying case class visible by using new
scala>enumCommand:caseResetcaseIncrementBy(inc: Int)
caseConfigure(init: Int, inc: Int)
scala>valinc=newCommand.IncrementBy(2) // `inc` IS a case classvalconf=newCommand.Configure(0, 5) // `conf` IS a case class
scala> println(s"inc.ordinal = ${inc.ordinal}")
inc.ordinal =1
scala>valconf1= conf.copy(inc =7)
println(conf1) // will print Configure(0, 7)Configure(0,7)
scala> conf1.<TAB> // which members are defined on this enum instance?
_2 wait canEqual formatted productPrefix
!= eq clone ensuring notifyAll productElement
## ne equals finalize asInstanceOf productIterator
-> inc notify getClass isInstanceOf productElementName
== copy ordinal hashCode productArity productElementNames
_1 init $ordinal toString synchronized
Scala 3's export clause - I
Scala 3's export clause allows us to create aliases for selected members
objectA:objectB:objectC:valx:Int=5exportB.C.x
We can now do the following:
scala>A.x
valres1:Int=5
We have only scratched the surface of the export clause. It enables us to compose new functionality rather than going through OOP's inheritance based approach. More details on this in the exportreference documentation
Scala 3's export clause - II
Composing functionality using export
privateclassHotAirOven:varon=falsevartempSetting=180defsetTemp(temp: Int):Unit= {tempSetting = temp; println(s"Setting temperature to $temp")}
defturnOn:Unit= on =truedefturnOff:Unit= on =falsedefstatus:String=s"Hot-air oven is ${if (on) "on"else"off"} - Temperature setting at $tempSetting”
privateclassMicrowaveOven:varon=falsevarpowerSetting=600defsetPower(watts: Int):Unit= {powerSetting = watts; println(s"Setting power to $powerSetting")}
defturnOn:Unit= on =truedefturnOff:Unit= on =falsedefstatus:String=s"Microwave oven is ${if (on) "on"else"off"} - Power setting at $powerSetting Watt"
scala>valoven=newCombiOvenvaloven:CombiOven=CombiOven@71065f9e
scala> println(oven.status)
Hot-air oven is off - temperature setting at 180Microwave oven is off -Power setting at 600Watt
scala> oven.setTemp(90);oven.setPower(900)
Setting temperature to 90Setting power to 900
scala> println(oven.status)
Hot-air oven is off - temperature setting at 90Microwave oven is off -Power setting at 900Watt
scala> oven.hotAirOn
scala> println(oven.status)
Hot-air oven is on - temperature setting at 90Microwave oven is off -Power setting at 900Watt
scala> oven.hotAirOff;oven.microwaveOn
scala> println(oven.status)
Hot-air oven is off - temperature setting at 90Microwave oven is on -Power setting at 900Watt
Summary
In this chapter, we have covered:
Scala 3's new features such as
enum: a concise manner to define enumerations and ADT's
export: enables the definition of new objects through composition as an alternative to inheritance
Using enums is easy, but there are still quite a few unknowns
No default exposure of the underlying case classes
Using enum and export
In this exercise, we will swap the sealed trait / case object / case class Akka protocol encoding with an enum based one
Make sure you're positioned at exercise "enum and export"
Follow the exercise instructions provided in the README.md file in the code folder