My question is that in the following snippet, c2 can pass compilation but t2 fail. why?
type PairT[A, B] = { //structural type
type T1 = A
type T2 = B
}
class PairC[A, B] {
type T1 = A
type T2 = B
}
case class TMap[A, B](a: A, b: B)
type MapC2[A] = TMap[p.T1, p.T2] forSome { val p: PairC[A, A] }
type MapT2[A] = TMap[p.T1, p.T2] forSome { val p: PairT[A, A] }
val c2: MapC2[Int] = TMap(1,2)
val t2: MapT2[Int] = TMap(1,2)
Recently I've had an interesting scala riddle that involves existential types and type aliases (https://softwaremill.com/scala-riddle) and I figured out that when type alias doesn't work we should try with bounded abstract type members.
I haven't figured out any pattern that could tell me which kind of type member I need to apply in particular situation. I can't find answer in the documentation, maybe it's an implementation detail?
I hope that there is someone who would help me find such pattern or at least give some new clues..
Inside PairT
I replaced type aliases (type T1 = A
) with tightly bounded abstract types (type T1 >: A <: A
) and .. it works (scalac 2.11.4).
What's more interesting - PairC
, which is a concrete class, will work only with type aliases - if I try to replace them with bounded abstract type members it raises a compilation error.
Below is the whole code, after my modifications:
package so1
import scala.language.existentials
object SOPuzzle {
type PairT[F, S] = {
type T1 >: F <: F
type T2 >: S <: S
}
class PairC[F, S] {
type T1 = F
type T2 = S
}
case class TMap[T, U](a: T, b: U) {
def consumeA(a: T): T = a
def consumeB(b: U): U = b
}
type MapC2[A] = TMap[p.T1, p.T2] forSome {val p: PairC[A, A]}
type MapC2V2[A] = TMap[PairC[A, A]#T1, PairC[A,A]#T2]
type MapT2[A] = TMap[p.T1, p.T2] forSome {val p: PairT[A, A]}
type MapT2V2[A] = TMap[PairT[A, A]#T1, PairT[A, A]#T2]
val c2: MapC2[Int] = TMap(1, 2)
val c2v2: MapC2V2[Int] = TMap(1, 2)
val t2: MapT2[Int] = TMap(1, 2)
val t2v2: MapT2V2[Int] = TMap(1, 2)
val i1:Int = c2.consumeA(0)
val i2:Int = c2.consumeB(0)
val i3:Int = c2v2.consumeA(0)
val i4:Int = c2v2.consumeB(0)
val i5:Int = t2.consumeA(0)
val i6:Int = t2.consumeB(0)
val i7:Int = t2v2.consumeA(0)
val i8:Int = t2v2.consumeB(0)
}
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