The answer, which tells that Scala enums do not support args/methods-customized values seems wrong. Other answers (some of them involve implicit
) demonstrate that it can do but they create impression that demands name duplication: your value has declared name as java object field and, secondly, the name is supplied to the value constructor as string whereas the whole point of Enums is to create a iterable name->value map and scala can do without redundancy:
object Ops1 extends Enumeration {
protected case class OpsVal(f: Int => Int) extends super.Val(/*nextId*/)
val ZERO = new FuncVal (x => 0)
val DOUBLE = new FuncVal (x => 2 * x )
implicit def convert(v: Value) = v.asInstanceOf[OpsVal]
}
// implicit is not needed
Ops1.ZERO.f(1) //> res0: Int = 0
// implicit is needed
Ops1.values map (v => (v + "=>" + v.f(1)))//> res1: scala.collection.immutable.SortedSet[String] = TreeSet(DOUBLE=>2, ZERO=>0)
I think that the above is more concise than
object Ops2 extends Enumeration {
protected abstract class OpsVal extends Val() {
def f(a: Int): Int
}
val ZERO = new OpsVal { def f(x: Int) = 0 }
val DOUBLE = new OpsVal { def f(x: Int) = 2 * x }
implicit def convert(valu: Value) = valu.asInstanceOf[OpsVal]
}
Ops2.ZERO.f(1) // implicit is not needed //> res2: Int = 0
// implicit is needed
Ops2_3.values map (v => (v, v(1))) //> res7: scala.collection.immutable.SortedSet[(e.Ops2_3.Value, Int)] = TreeSet
//| ((ZERO,0), (DOUBLE,2))
Since there is a single method per value, we can convert them into the functions
object Ops2_3 extends Enumeration {
protected case class FuncVal(f: Int => Int) extends Val {
def apply(x: Int) = f(x) // no need to extend Function1 explicitly
}
val ZERO = new FuncVal (x => 0)
val DOUBLE = new FuncVal (x => 2 * x )
implicit def convert(v: Value) = v.asInstanceOf[FuncVal]
}
Ops2_3.ZERO(1) // implicit is not needed //> res6: Int = 0
// implicit is needed
Ops2_3.values map (v => (v, v(1))) //> res7: scala.collection.immutable.SortedSet[(e.Ops2_3.Value, Int)] = TreeSet
//| ((ZERO,0), (DOUBLE,2))
Functions, shared among all values, can be defined like this (usable in arg parser)
val args: Array[String] = "-silent -samples 100 -silent ".split(" +").toArray
//> args : Array[String] = Array(-silent, -samples, 100, -silent)
object Opts extends Enumeration {
val nopar, silent, samples = new Val() {
def apply() = args.contains(toString)
def asInt(default: Int) = { val i = args.indexOf(toString) ; if (i == -1) default else args(i+1).toInt}
def asInt: Int = asInt(-1)
override def toString = "-" + super.toString
}
}
Opts.nopar() //> res0: Boolean = false
Opts.samples.asInt //> res1: Int = 100
Other users argue for cases of sealed traits + macros, Iteration over a sealed trait in Scala?