Search code examples
scalatype-inferenceshapelesssingleton-type

Can I obtain an unwrapped singleton type in Scala with a simple method?


In Scala, in a discussion around Miles Sabin's shapeless library, I've seen code like this:

def sing[T <: String](t: T): Option[t.type] = Some(t)

where something like this:

val name = sing("name")

has type Option[Constant(name).type]. I thought “why wrap it in an Option”? But if I try this:

def sing2[T <: String](t: T): t.type = t
val name2 = sing2("name")

then name2 has type String, whereas I would have expected it to be Constant(name).type. What am I missing? Is there a workaround that does not involve wrapping the singleton type?


Solution

  • This is a known quirk of scalac.

    Singleton types are a compiler internal and they've been there for a long time, but they've never been meant to be exposed to the users. So, there's no guarantee about their "API" and as a matter of fact scalac tries to make them "disappear" whenever it can.

    This is pretty much the reason why Miles had to use a Witness type to wrap singleton types whenever needed (e.g. extensible record keys).

    Apparently, wrapping them in a container causes the compiler to retain the actual type, and this is what happens with Option.

    As Oleg mentioned in the other answer, there's an ongoing effort to make singleton type officially part of the language: http://docs.scala-lang.org/sips/pending/42.type.html