Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exchanging a type parameter's upper bound for an evidence parameter

I want to relax the constraints on a trait's type parameter and instead impose them on a method in the form of an evidence parameter. Given some skeletal setup:

trait State[Repr]
object Observer {
  def apply[Repr <: State[Repr]](reader: Reader[Repr]): Observer[Repr] = 
    new Observer[Repr] {}
}
trait Observer[A]
trait Reader  [A]

This works:

trait StateX[Repr <: StateX[Repr]] extends State[Repr] { 
  protected def reader: Reader[Repr]
  def observe: Observer[Repr] = Observer(reader)
}

And this doesn't:

trait StateY[Repr] extends State[Repr] { 
  protected def reader: Reader[Repr]
  def observe(implicit ev: Repr <:< State[Repr]): Observer[Repr] = Observer(reader)
}

With message "inferred type arguments [Repr] do not conform to method apply's type parameter bounds [Repr <: State[Repr]]". Since the evidence ev suggests this conformation, I wonder how StateY can be fixed.

like image 577
0__ Avatar asked Jan 02 '12 15:01

0__


1 Answers

Your problem is that even though evidence of the form A <:< B implies that a value of type A can be converted to a value of type B it doesn't imply A <: B ... indeed, the main reason for using a type constraint or a view bound rather than an ordinary type bound is precisely because such a subtype relationship doesn't hold.

Consequently the constraint in StateY, Repr <:< State[Repr], isn't sufficient to satisfy the bound Repr <: State[Repr] on Observer's apply method. Given that you want to relax the constraint on StateX's type parameter your only option is to weaken the constraint on the apply method's type parameter correspondingly. That gets you something like the following using a view bound instead of an ordinary type bound,

object Observer {
  def apply[Repr <% State[Repr]](reader : Reader[Repr]) : Observer[Repr] =
    new Observer[Repr] {}
}

or alternatively,

object Observer {
  def apply[Repr](reader : Reader[Repr])
                 (implicit ev : Repr <:< State[Repr]) : Observer[Repr] =
    new Observer[Repr] {}
}

if you'd rather use constraints throughout.

like image 88
Miles Sabin Avatar answered Sep 28 '22 01:09

Miles Sabin