Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala Structural type and existential type issue

Tags:

scala

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)
like image 450
chenhry Avatar asked Jul 15 '13 06:07

chenhry


1 Answers

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..

How I made your code working

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)
}
like image 190
Marcin Kubala Avatar answered Oct 31 '22 14:10

Marcin Kubala