typelevel / scala

Typelevel Scala, a fork of Scala
http://typelevel.org/scala/
372 stars 21 forks source link

Singleton types for function return values #155

Closed tindzk closed 7 years ago

tindzk commented 7 years ago

Presently, singleton types cannot be used with function return values:

def f[T <: Singleton](t: T) = t

val x  = "test"
def x2 = "test"

f(x)   // Returns `x.type`
f(x2)  // Does not compile

I stumbled upon this limitation when I wanted to define a wrapper for strings which may also be singleton types. Here is an example:

case class Wrap[T <: Singleton](value: String with T)

In cases, where we do not care about the singleton type, we could return Wrap[_] from functions:

def str = "test"

def f()          : Wrap[_] = Wrap("test")
def f2(s: String): Wrap[_] = Wrap(s)
def f3()         : Wrap[_] = Wrap(str)  // Does not compile

As the type of value is String with T, we can access it without casting:

val s : String = f().value
val s2: String = f2("test").value
val s3: String = f3().value
milessabin commented 7 years ago

I think you're misunderstanding how type inference is working in these cases. In your first example note that the inferred type of val x is the singleton type of the stable identifier x, not the literal type "test" that you were most likely expecting. The use of x2 is rejected because it isn't a stable identifier. In the val x case you will get the behaviour you are expecting if you mark the val as final. In the def x2 case you will need to provide an explicit result type.