简体   繁体   中英

Features of different kinds of path-dependent types in scala

Suppose there is a trait:

trait OuterTrait {
  type InnerType
}

Now we can write non-generic function someAlgo :

def pairToString[S, U](x: S, y: U): String = 
  "{" + y.toString + " in " + x.toString + "}"

def pairPrintln[S, U](x: S, y: U) {
  println(pairToString(x, y))
}

def someAlgo(x: OuterTrait)(y: x.InnerType): x.InnerType = {
  pairPrintln(x, y)
  y
}

and series of generic functions:

def someAlgoObjObj[T <: OuterTrait](x: T)(y: x.InnerType): x.InnerType = {
  pairPrintln(x, y)
  y
}

def someAlgoObjType[T <: OuterTrait](x: T)(y: x.InnerType): T#InnerType = {
  pairPrintln(x, y)
  y
}

def someAlgoTypeType[T <: OuterTrait](x: T)(y: T#InnerType): T#InnerType = {
  pairPrintln(x, y)
  y
}

And one more generic function doesn't compile:

def someAlgoTypeObj[T <: OuterTrait](x: T)(y: T#InnerType): x.InnerType = {
  pairPrintln(x, y)
  y
}

It seems that: 1) someAlgo and someAlgoObjObj are the most correct functions; 2) and there is no sense to use generic function in this example at all.

And I would like to clarify some differences between generic functions above. Please, correct me, If I make errors.

So as I understand type T corresponds to static type of x (call it X ) or explicit type of generic call (I mean algo[Int] for instance). That's why T#InnerType corresponds to type in declaration of type X . But x.InnerType also corresponds to InnerType of static type of x . Where is the difference?

Further... someAlgoObjType compiles, so it seems that x.InnerType must be subtype of T#InnerType . Then it is OK that someAlgoTypeObj doesn't compile, since we can't make downcast implicitly. Though we can rewrite last one:

def someAlgoTypeObj[T <: OuterTrait](x: T)(y: T#InnerType): x.InnerType = {
  pairPrintln(x, y)
  y.asInstanceOf[x.InnerType]
}

UPD1: I found one difference between someAlgoObjObj and someAlgoTypeType if use them with explicit type parameter. If we write some class extending OuterTrait :

class OuterIntClass extends OuterTrait{
  type InnerType = Int
}
val x: OuterIntClass = new OuterIntClass()
val y: Int = 5

Then:

someAlgoObjObj[OuterTrait](x)(y) // OK

and next call doesn't work:

someAlgoTypeType[OuterTrait](x)(y)

T#InnerType means "A InnerType belonging in some T" while x.InnerType means "A InnerType belonging in a given x (of type OuterTrait)".

The key here in understanding these is in some T vs in a given x . You can interpret in some as some T but we don't which T instance , meaning that in a two Ts aren't necessarily the same, so, T#InnerType can't be proven to be equal to another T#InnerType.

Let's analyze the signatures:

/* 1 */ def someAlgoObjObj[T <: OuterTrait](x: T)(y: x.InnerType): x.InnerType = ???
/* 2 */ def someAlgoObjType[T <: OuterTrait](x: T)(y: x.InnerType): T#InnerType = ???
/* 3 */ def someAlgoTypeType[T <: OuterTrait](x: T)(y: T#InnerType): T#InnerType = ???
  1. Given x and InnerType belonging in this x returns the its InnerType.
  2. Given x and InnerType belonging in this x returns InnerType belonging to some T , meaning a some T is not necessarily the same instance as x.
  3. Given x and InnerType belonging to some T returns InnerType belonging to some T

Now for the forth one:

def someAlgoTypeObj[T <: OuterTrait](x: T)(y: T#InnerType): x.InnerType = y

The signature reads: given x and InnerType belonging to some T , returns the InnerType belonging to this x . But in the implementation, we try to return y, which belongs to a T that's not necessarily the same as x, hence the compiler complains.

Little note about update .

someAlgoTypeType[OuterTrait](x)(y) 

Failes because your method signature tells that it expects its y parameter to conform to the type T#InnerType and your y.type is Int. To make it work you should change it's type to the following:

class OuterIntClass extends OuterTrait{
  type InnerType = Int
}
val x: OuterIntClass = new OuterIntClass()
val y: x.InnerType = 5

Now y 's type satisfies type projection T#InnerType and someAlgoTypeType[OuterTrait](x)(y) compiles

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM