Add a static ordinal
method to non-singleton enum
cases
#17862
Replies: 0 comments 8 replies
-
Provided there aren't any objections, I'd be happy to implement this small feature. I understand that something like the full optimization of |
Beta Was this translation helpful? Give feedback.
-
I am not sure of the use case you need a static method for, because in pattern matching the instance |
Beta Was this translation helpful? Give feedback.
-
@bishabosha are you sure? Here's the elaborated desugaring I had in mind. Please let me know if you see how I would do this efficiently without a static method. I get that it is really tempting to just switch on the Initial codeenum Expr {
case Literal(i: Int)
case Add(lhs: Expr, rhs: Expr)
case Minus(lhs: Expr, rhs: Expr)
case If(cond: Expr, ifNonZero: Expr, ifZero: Expr)
}
def eval(e: Expr, context: Map[String, Int]): Int =
e match {
case Expr.Literal(i) => i
case Expr.Add(lhs, rhs) => lhs.eval() + rhs.eval()
case Expr.Minus(lhs, rhs) => lhs.eval() - rhs.eval()
case Expr.If(cond, ifNonZero, ifZero) => if (conf.eval() != 0) ifTrue.eval() else ifFalse.eval()
} Scala pseudo-code for the desugaring// this class needn't be statically defined - it could be a `Lookup::hiddenClass` from an `invokedynamic`
class eval$matchMap$Expr {
@static
val matchCases = {
val c = new Array[Int](4) // initial all zeroes
try { c[Expr. Expr.Literal.ordinal()] = 1 } catch { case _: NoSuchFieldError => /* skip */ }
try { c[Expr.Add.ordinal()] = 2 } catch { case _: NoSuchFieldError => /* skip */ }
try { c[Expr.Minus.ordinal()] = 3 } catch { case _: NoSuchFieldError => /* skip */ }
try { c[Expr.If.ordinal()] = 4 } catch { case _: NoSuchFieldError => /* skip */ }
c
}
}
def eval(e: Expr, context: Map[String, Int]): Int = {
(eval$matchMap$Expr.matchCases[e.ordinal]: @switch) match {
case 1 =>
val Expr.Literal(i) = e.asInstanceOf[Expr.Literal]
i
case 2 =>
val Expr.Add(lhs, rhs) = e.asInstanceOf[Expr.Add]
lhs.eval() + rhs.eval()
case 3 =>
val Expr.Minus(lhs, rhs) = e.asInstanceOf[Expr.Minus]
lhs.eval() - rhs.eval()
case 4 =>
val Expr.If(cond, ifNonZero, ifZero) = e.asInstanceOf[Expr.If]
if (conf.eval() != 0) ifTrue.eval() else ifFalse.eval()
case _ => throw new IncompatibleClassChangeError() // an enum case got added without recompiling `eval`!
} |
Beta Was this translation helpful? Give feedback.
-
Isn't it accepted that enum ordering is API and you can't muck with it? |
Beta Was this translation helpful? Give feedback.
-
I don't understand this comment. Yes, the values outputted by Java's |
Beta Was this translation helpful? Give feedback.
-
Sorry, middle of the night here and I said the opposite thing. Ordinal is what you don't rely on to be stable. Java enum serialization uses the name, for example. |
Beta Was this translation helpful? Give feedback.
-
I understand that the ordinal is unstable, but the name is not a good switch target (the JVM switches on ints, not strings). Does the sample desugaring of how we might efficient compile a Although you shouldn't serialize the ordinal directly, you could play a similar desugaring trick (list out the variants in an array that is dynamically populated) to derive some locally stable ordering. |
Beta Was this translation helpful? Give feedback.
-
+1. |
Beta Was this translation helpful? Give feedback.
-
In a nutshell: it should be possible to extract the
ordinal
associated with all cases of anenum
, even if they aren't singletons. Right now, this is only possible to do with an instance on hand.The change needed is pretty trivial too: for the
final case class
's generated in Translation of Enums and ADTs: case 9, we make sure that the class also contains a staticordinal
method as well as an instance method.Additional motivation
This would enable future optimizations, eg. to support translating
match
onenum
into alookupswitch
/tableswitch
(as Java does). The usual trick there is to build up a static array of switch integer labels using ordinals in thematch
, and then switch on the value found in this array at the index of the scrutiny's ordinal (unfortunately this is the best online description I could find, although this can also be inspected pretty easily by inspecting the bytecode produced by Java code switching on anenum
). That static array can't be constructed if the ordinals for the cases aren't also statically queryable.Beta Was this translation helpful? Give feedback.
All reactions