Scala Structural type and existential type problem

My question is, in the next snippet, c2 can pass compilation, but t2 fails. 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) 
+6
source share
2 answers

I recently had an interesting scala riddle that includes existential types and type aliases ( https://softwaremill.com/scala-riddle ), and I realized that when the type alias does not work, we should try the restricted members of the abstract type.

I did not understand any template that could tell me which type of type member I need to apply in a particular situation. I can not find the answer in the documentation, maybe this is an implementation detail?

I hope there is someone who can help me find such a template or at least give some new tips.

How I worked with your code

Inside PairT I replaced type aliases ( type T1 = A ) with strictly restricted abstract types ( type T1 >: A <: A ) and .. it works (scalac 2.11.4).

What's even more interesting is that PairC , which is a concrete class, will only work with type aliases - if I try to replace them with restricted members of an abstract type, it will cause a compilation error.

Below is all the 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) } 
+1
source

I think this is an output error (or maybe a limitation) regarding the type construct.

Edit: The error message was the first that made me think it was an error:

", found: Requires Int (1): A

If you divide the last line by 2, i.e.

 val t3 = TMap(1,2) val t2: MapT2[Int] = t3 

then it gives a similar message:

"found: Test1.this.TMap [Int, Int] required: Test1.this.MapT2 [Int] (which expands to) Test1.this.TMap [A, A]"

Given that A is a symbol and Int is a class, it looks like it compares apples and oranges. Sorry, I can’t take this logic further!

0
source

Source: https://habr.com/ru/post/949439/


All Articles