New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Subclass Enumeration to allow case classes etc. to function as enums #2111
Comments
Imported From: https://issues.scala-lang.org/browse/SI-2111?orig=1 |
@phaller said: val Colors = new CaseEnum {
sealed abstract class Color extends Case
case class Red extends Color
case class Blue extends Color
Red()
Blue()
}
Colors.foreach {c=> println("Value "+c+" is mapped to "+Colors.cases(c))} With objects this is not necessary, since you are referencing them using reflection in your for-comprehension. Otherwise, I'll bring your |
Naftoli Gugenheim (naftoligug) said: class CaseEnum extends Enumeration {
type CASE <: Case
private val _cases = new scala.collection.mutable.HashMap[Int, CASE]
trait Case { this: CASE =>
private lazy val _id = nextId
private lazy val _name = {
val name = getClass.getName
if(name.endsWith("$$"))
name.substring(name.lastIndexOf("$$", name.length-2)+1, name.length-1)
else
name.substring(name.lastIndexOf("$$") + 1)
}
def name = _name
def id = _id
lazy val value = Value(id, name)
private[CaseEnum] def init = {
_cases += (value.id -> this)
}
}
def cases(v: Value) = _cases(v.id)
def cases(id: Int) = _cases(id)
def cases(name: String) = _cases.values.find(_.name==name).get
import scala.util.Sorting._
def cases = stableSort(_cases.values.collect, (c:CASE)=>c.id)
import java.lang.reflect.Method
for {
m <- stableSort(getClass.getMethods.toSeq, (a:Method,b:Method)=>(a.getName < b.getName))
if m.getReturnType.getName.endsWith("$$"+m.getName+"$$") &&
m.getParameterTypes.length==0 &&
classOf[Case].isAssignableFrom(m.getReturnType)
} {
m.invoke(this).asInstanceOf[Case].init
}
} This version has a small improvement to a basic problem; maybe you have a better solution. Previously, the members were essentially assigned ids in the order they were returned by reflection. This order is not stable between rebuilds of the program. I therefore added code to sort them alphabetically. This of course does not solve the problem of adding elements later. Support was also added for setting the id. For example: class Priorities extends CaseEnum {
type CASE = Priority
case class Priority(override val id: Int) extends Case
case object Routine extends Priority(0)
case object Urgent extends Priority(1)
case object Emergency extends Priority(2)
} More methods were added for looking up members, Also, a type member was added to solve a basic problem: CaseEnum needs to know the exact type it's supposed to return from cases(). |
@phaller said: As for the other parts of the proposal, we decided not to allow The improvements we agreed on in the meeting are implemented in r19311 (trunk) with a test in |
As was discussed on the list, Enumeration lacks the advantages of being object oriented, while case classes/objects lack the advantages of being enumeratable. A simple subclass of Enumeration, which I would like to contribute to the standard library, solves this problem. The idea of using reflection to solve the problem of lazy object intialization comes from lift's MetaMapper.
This only works for
or
but for
you have to reference the members in the body,
e.g.
Example usage:
Note that members do not actually have to be case classes or case objects.
Also, I haven't tested it on 2.8. Is there a significant difference in Enumeration?
Here is my source code:
The text was updated successfully, but these errors were encountered: