Why is this requiring an existential type that is expanding to include Singleton?

83 Views Asked by At

In this Scala 2.13 example:

import scala.language.implicitConversions

object Main extends App {

  trait Choosable {
    type T
    type Choose = this.type => T
    @inline implicit def choice(choose: Choose): T = choose(this)
  }

  object Choosable {
    implicit class ChooseOps[C <: Choosable](private val choose: C#Choose) extends AnyVal {
      def display(implicit choice: C#Choose => C#T): String = choice(choose).toString
    }
  }

  object Color extends Choosable {
    override type T = String
    val Red: T = "Red"
    val Blue: T = "Blue"
  }

  def displayChosenColor(color: Color.Choose): Unit = {
    println(Choosable.ChooseOps[Color.type](color).display(Color.choice))
  }

  displayChosenColor(_.Red)
}

It fails with:

type mismatch;
 found   : Main.Color.Choose => Main.Color.T
    (which expands to)  (Main.Color.type => String) => String
 required: (_1.type => _1.T forSome { val _1: Main.Color.type }) => Main.Color.T
    (which expands to)  (Function1[_ <: Main.Color.type with Singleton, String]) => String
    println(Choosable.ChooseOps[Color.type](color).display(Color.choice))

Why is an existential type?

Why is that existential type expanding to (Function1[_ <: Main.Color.type with Singleton, String]) => String?

Is there a way too get display to require a Main.Color.Choose => Main.Color.T?


This Q&A (Scala trait `this.type` in type parameter) gives some clues that it might have something to do with this.type.

I get that this.type is the Singleton type which denotes the set containing only this.

In my case, C is Color.type which denotes the set containing only Color.

We can see from the error that Color.choice has the type (Main.Color.type => String) => String.

The thing that I don't get is the existential type _1.type => _1.T forSome { val _1: Main.Color.type }. Why is that not the same as Main.Color.type => String?

0

There are 0 best solutions below