Description
Type-safe generic methods operating on Enumerations and returning a Value need to have signatures of the form
def method[E <: Enumeration](e: E): E#Value
since it is not possible to specify the type of a particular instance:
def cantDoThis[E <: Enumeration](e: E): e.Value
The former is arguably typesafe enough, but unfortunately there is a bug in the implementation of inner class types inside objects:
object BugTestCase {
object Broken extends Enumeration { val zero = Value }
def getZero[E <: Enumeration](enum: E): E#Value = enum.withName("zero")
val correctlyTyped = getZero(Broken)
val wronglyTyped: Broken.type#Value = null
// val shouldWork: Broken.type#Value = getZero(Broken)
class Workaround extends Enumeration { val zero = Value }
lazy val Working = new Workaround
val actuallyWorks: Workaround#Value = getZero(Working)
}
Note that the Workaround class/lazy val pair should be equivalent to a companion object, but there is no way to write the correct type signature for the companion object. Although type inference works correctly, the REPL reports:
scala> BugTestCase.correctlyTyped
res0: BugTestCase.Broken#Value = zero
scala> BugTestCase.wronglyTyped
res1: BugTestCase.Broken.Value = null
This makes it necessary to use one's own singleton objects instead of the language-supported ones. Either Broken.type#Value should mean Broken$$#Value (where Broken$$ is the class of the singleton object), or Broken#Value should be valid syntax and mean that, or E#Value should be equivalent to Broken.Value.