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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With