Greg
Greg

Reputation: 11512

Can I use Enumerations as type parameters in Scala?

I'd like to use an Enumeration as a type parameter by the compiler is giving me grief.

object VehicleClass extends Enumeration {
  type VehicleClass = Value
  val Land, Air, Sea = Value
}
import VehicleClass._

trait Vehicle[K <: VehicleClass] { val kind: K }
case class Car(passengers: Int) extends Vehicle[Land] { val kind: Land }

Compiler complains:

[error] /Users/me/test/scala/co.blocke.scalajack/json/test.misc/Greg.scala:18: not found: type Land
[error] case class Car(passengers: Int) extends Vehicle[Land] { val kind: Land }
[error]                                                 ^
[error] /Users/me/test/scala/co.blocke.scalajack/json/test.misc/Greg.scala:18: not found: type Land
[error] case class Car(passengers: Int) extends Vehicle[Land] { val kind: Land }
[error]                                                                   ^

How can this be done?

Upvotes: 2

Views: 825

Answers (2)

iain
iain

Reputation: 10928

Alexey has provided the correct answer for using scala.Enumeration

I would address this problem using an ADT instead of enumerations which I regard as deprecated. (See http://underscore.io/blog/posts/2014/09/03/enumerations.html)

Here is the solution using ADTs

// Using an abstract class makes accessing things in VehicleClass companion 
// object nicer
sealed abstract class VehicleClass

case object Land extends VehicleClass
case object Air extends VehicleClass
case object Sea extends VehicleClass

trait Vehicle[K <: VehicleClass] { val kind: K }
case class Car(passengers: Int) extends Vehicle[Land.type] { val kind = Land }

I would simplify this code somewhat, as generally do not see the requirement to make the trait Vehicle generic. What extra safety does this add to your code? I would generally simplify the trait to

trait Vehicle { val kind: VehicleClass }

(The only reason I can see to make Vehicle generic would be to define type class instances for Vehicle[Land] instead of for all of the types of Vehicle[Land], but then Vehicle would probably need more members.)

Upvotes: 1

Alexey Romanov
Alexey Romanov

Reputation: 170713

You can write

case class Car(passengers: Int) extends Vehicle[Land.type] { 
  val kind: Land.type = Land 
}

Land.type is the singleton type of Land, i.e. the type whose only value is Land (not including null).

Upvotes: 2

Related Questions