I'm trying to create a method that takes a Scala 3 enum
as parameter, but this does not work, is this possible?
I try to do something like
trait Named:
def name: String
enum Birds(val name: String) extends Named:
case Sparrow extends Birds("Sparrow")
case Eagel extends Birds("Eagel")
case Colibri extends Birds("Colibri")
enum Dogs(val name: String) extends Named:
case Labrador extends Dogs("Labrador")
case Dalmatian extends Dogs("Dalmatian")
case Beagel extends Dogs("Beagel")
def showName[E <: Named](e: Enum[E]) = {
e.values.map(v => println(v.name))
}
showName(Birds)
showName(Dogs)
https://scastie.scala-lang.org/B0RbB7CxRMagTBVodrSQVQ
Found: Playground.Birds.type / Playground.Dogs.type
Required: Enum[E]
where: E is a type variable with constraint <: Playground.Named
One way would be to use reflection and define a structural type with all the methods generated in the enum companion:
import scala.reflect.Selectable.reflectiveSelectable
type EnumOf[E] = {
def values: Array[E]
def valueOf(name: String): E
def fromOrdinal(ordinal: Int): E
}
def showName[E <: Named](e: EnumOf[E]) = {
println(e.values.map(_.name).mkString(", "))
}
showName(Birds) // Sparrow, Eagel, Colibri
showName(Dogs) // Labrador, Dalmatian, Beagel
We would call .values
to obtain an Array[E]
, and then on each element call .name
(because you defined def name
on enum values buy not on enum companion object). Since it's array we have to convert it to List/Vector/String/etc since Array doesn't show anything useful with its toString
method.
To avoid reflection you'd have to define some common interface that companion object would implement (because OOTB there isn't one) like:
trait EnumOf[E] {
def values: Array[E]
def valueOf(name: String): E
def fromOrdinal(ordinal: Int): E
}
trait Named:
def name: String
enum Birds(val name: String) extends Named:
case Sparrow extends Birds("Sparrow")
case Eagel extends Birds("Eagel")
case Colibri extends Birds("Colibri")
object Birds extends EnumOf[Birds]
enum Dogs(val name: String) extends Named:
case Labrador extends Dogs("Labrador")
case Dalmatian extends Dogs("Dalmatian")
case Beagel extends Dogs("Beagel")
object Dogs extends EnumOf[Dogs]
// no need for reflectiveSelectable
def showName[E <: Named](e: EnumOf[E]) = {
println(e.values.map(_.name).mkString(", "))
}