0
votes

The following code does not compile on Scala 2.12 / 2.13. Why?

class X[U, T]

object X {
  implicit def genericX[U, T](implicit ev: T <:< U): X[U, T] = new X[U, T]
}

implicitly[X[AnyRef, String]]  // compiles
implicitly[X[String, Nothing]] // does not compile
1
Thanks @dmytro-mitin, I know that +T solves the problem, but unfortunately this is not what I can accept there. In fact, I would like to have T contravariant, but got stuck even in the invariant case.Kamil Kloch
Why do you need X? Now it's basically a synonym for <:<. Why can't you use <:< directly? Why do you need implicit to be resolved for Nothing? How does Nothing appear in your code?Dmytro Mitin
It is a bit complex and relates to stackoverflow.com/questions/61890200/…. Ultimately I would like to have a method def check[T](....): A[T] = ??? so that check(...) returns A[Any] while check[String](...) returns A[String]. (i.e. Any inferred as a default type, instead of Nothing). I tried the following: def check[T](implicit ev: X[Any, T]): A[T] = ??? and hence X[U, -T].Kamil Kloch
Thanks for the feedback! Let me paint the whole picture: A[T] captures ClassTag[T] inside. I am looking for a method def attribute[T](s: String): A[T], which returns A[SomeDefaultType] when T is missing (aor even Any, to make things simpler). I do have a working solution (gist.github.com/kamilkloch/a5c97d0c7cdec47f8dc4c4ac4c131674), however, it requires an intermediate class to curry type parameters. I was hoping to get rid of it with the aforementioned X[U, -T].Kamil Kloch

1 Answers

2
votes

Long story short, compiler doesn't like to infer Nothing in implicits.

Why doesn't Scala's implicit class work when one of the type parameters should be Nothing?

Implicit error when trying to implement the `Absurd` typeclass

https://www.reddit.com/r/scala/comments/73791p/nothings_twin_brother_the_better_one/

http://guillaume.martres.me/talks/typelevel-summit-oslo/?fbclid=IwAR1yDSz-MetOgBh0uWMeuBuuL6wlD79fN_4NrxAtl3c46JB0fYCYeeGgp1Y#/9 (slide 10 "The fear of Nothing")

https://www.youtube.com/watch?v=YIQjfCKDR5A?t=459 (7:39)

https://www.youtube.com/watch?v=lMvOykNQ4zs

The fear of Nothing

  • scalac instantiates eagerly, even when it isn't safe

  • Counterbalanced by never inferring Nothing

    class Foo[T] { def put(x: T) = {} }
    (new Foo).put("") // T? = String
    
  • Fails if the lower bound isn't Nothing

    class Foo[T >: Null] { def put(x: T) = {} }
    (new Foo).put("") // T? = Null
    // type mismatch: Null does not match String
    
  • Sometimes you really want to infer Nothing!

    class Foo[T]
    def foo[T](x: Foo[T]) = x
    foo(new Foo[Nothing]) // error
    

Workaround is to introduce type Bottom

type Bottom <: Nothing

implicitly[Bottom =:= Nothing]
implicitly[Nothing =:= Bottom]

implicitly[X[AnyRef, String]]  // compiles
// implicitly[X[String, Nothing]] // does not compile
implicitly[X[String, Bottom]] // compiles