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