In Java 1.6.0_21, the first example below compiles fine, and I think that's because the parameter type bounds are bare. That is, in the "Z extends Zen" bound below, Java allows Zen to slide by as the name of a raw, non-generic type (equivalent to the runtime "erased" type). This might be wrong and bad, but it also can be useful, or at least wacky good times on the bus ride home:
public class CorefTest {
public static interface Tao<Z extends Zen> {
}
public static interface Zen<T extends Tao> {
}
}
In Scala 2.8.0.final, the below compiles great up through CleanOceanWithFish, showing some basic type param hookups. But when we get to Zen and Tao being interdependent generic types, the Scala compiler rejects my weaving construct. See compiler errors in comments.
package heaven.piece
class Lucky {
trait Water {}
trait CleanWater extends Water {}
trait Sea [W <: Water] {}
trait Fish[S <: Sea[CleanWater]] {}
trait CleanOceanWithFish[F <: Fish[CleanOceanWithFish[F]]]
extends Sea[CleanWater]{}
// Above code compiles fine, but the type constructor pair below doesn't compile
trait Tao[Z <: Zen[Tao[Z]]]{};
trait Zen[T <: Tao[Zen[T]]]{};
}
// error: type arguments [Lucky.this.Tao[Z]] do not conform to trait Zen's
// type parameter bounds [T <: Lucky.this.Tao[Lucky.this.Zen[T]]]
// error: type arguments [Lucky.this.Zen[T]] do not conform to trait Tao's
// type parameter bounds [Z <: Lucky.this.Zen[Lucky.this.Tao[Z]]]
So, how can I properly tie the Scala (2.8.0) knot between Tao and Zen?
It's certainly a contrived example, but what I really want is to use Scala to extend some real Java types I have working in the above form (which existential types via "forSome" and "[_]" are not helping me with, so far). I think that getting Zen and Tao compiling in Scala will probably show the way to that Java extension. If you can consider the Java extension issue in your answer, so much the better. Thanks for any help!
Update posted after the very helpful first two answers below from Nikita S. and Kris N.
I empirically learned some more about various Java+Scala coreference scenarios. The upshot is that when we want interoperable coreferent types in both Java and Scala, then this Java construct:
public static interface JavaFunTao<JFZ extends JavaFunZen<? extends JavaFunTao<JFZ>>> {
public JFZ consider(JFZ someZen, JavaFunTao<JFZ> otherTao);
}
public static interface JavaFunZen<JFT extends JavaFunTao<? extends JavaFunZen<JFT>>> {
public JFT meditate(JFT someTao, JavaFunZen<JFT> otherZen);
}
provides more specific typing than my first Java example at top (avoiding the raw types), and is then properly extensible in Scala as follows:
class HiFunTao[HFZ <: HiFunZen[ _ <: HiFunTao [HFZ]]] extends JavaFunTao[ HFZ] {
override def consider(someZen: HFZ, otherTao: JavaFunTao[HFZ]) : HFZ = {
println (this.toString() + " is considering " + someZen + " and " + otherTao);
someZen
}
}
class HiFunZen[HFT <: HiFunTao[ _ <: HiFunZen [HFT]]] extends JavaFunZen[ HFT] {
override def meditate(someTao: HFT, otherZen: JavaFunZen[HFT]) : HFT = {
println (this.toString() + " is meditating on " + someTao + " and " + otherZen);
someTao
}
}
I verified that we can make simple concrete types based on these, instantiate them, and invoke their methods. The key step in both the Java and the Scala is placing the bounded wildcard at the point where the type parameter tree loops back into the current declaration type, i.e. the "? extends" in java, and the "_ <:" in Scala.