Re: On inference of existential types
Andrew Phillips <[email protected]> Sat, 21 May 2016 11:13:02 -0700 (PDT)
| Newsgroups | gmane.comp.lang.scala |
|---|---|
| Message-ID | <[email protected]> |
Hi Guanpeng!
The second part of your example - instantiating a Q of Q - compiles in
Scala for me (2.11.6) if we simply let the compiler figure out the types:
scala> val q = new Q(new Q())
q: Q[Nothing] = Q@3294fb9d
scala> val b = Q.g(q) // works
java.lang.UnsupportedOperationException
at Q.g(Q.java:22)
... 33 elided
scala> val q2: Q[Q[Int]] = new Q(new Q()) // now with Int
q2: Q[Q[Int]] = Q@27606b76
scala> val b = Q.g(q2)
java.lang.UnsupportedOperationException
at Q.g(Q.java:22)
... 33 elided
The variant with the array is a little trickier example because it's
difficult to compare directly to Java, since Java doesn't support generic
arrays. The comparison is more direct if we change the Java class to use
types that support generics in Java, too, e.g.
public static <T> Q<T> fprime(List<Q<? extends T>> qs) {
throw new UnsupportedOperationException();
}
public static <T, S extends T> Q<T> fdoubleprime(List<Q<S>> qs) {
throw new UnsupportedOperationException();
}
With this example, we can get fdoubleprime to compile by letting the
compiler figure out the type variables for T and S:
scala> import collection.JavaConverters._
scala> val qs: Seq[Q[Int]] = Seq(new Q())
qs: Seq[Q[Int]] = List(Q@11cb7a27)
scala> val a2 = Q.fdoubleprime(qs.asJava)
java.lang.UnsupportedOperationException
at Q.fdoubleprime(Q.java:18)
... 33 elided
The fprime bit is trickier, though. Here, Scala seems to need a type hint,
where Java doesn't:
scala> val qs: Seq[Q[_ <: Int]] = Seq(new Q())
qs: Seq[Q[_ <: Int]] = List(Q@ea66840)
scala> val a = Q.fprime(qs.asJava) // fails to compile
scala> val a: Q[Int] = Q.fprime(qs.asJava) // fails to compile
scala> val a = Q.fprime[Int](qs.asJava) // works
java.lang.UnsupportedOperationException
at Q.fprime(Q.java:14)
... 33 elided
This differs from Java, which *does* allow the equivalent call to compile:
public static void callFprime() {
List<Q<? extends Integer>> qs = new ArrayList<Q<? extends
Integer>>();
fprime(qs);
}
The hint is also required if we define the equivalent method in Scala:
scala> def fprimeInScala[T](qs: Seq[Q[_ <: T]]): Q[T] = ???
fprimeInScala: [T](qs: Seq[_ <: T])Q[T]
val a3 = fprimeInScala(qs) // fails to compile
val a3: Q[Int] = fprimeInScala(qs) // fails to compile
scala> val a3 = fprimeInScala[Int](qs) // works
scala.NotImplementedError: an implementation is missing
at scala.Predef$.$qmark$qmark$qmark(Predef.scala:225)
at .fprimeInScala(<console>:10)
... 33 elided
We can call the Scala method successfully without the explicit type hint if
we drop the wildcard type:
scala> val qs2: Seq[Q[Int]] = Seq(new Q()) // no wildcard
qs2: Seq[Q[Int]] = List(Q@68461613)
scala> val a3 = fprimeInScala(qs2) // works
scala.NotImplementedError: an implementation is missing
at scala.Predef$.$qmark$qmark$qmark(Predef.scala:225)
at .fprimeInScala(<console>:10)
... 33 elided
An interesting note is that the equivalent call to Java does not work
since, unlike Seq, java.util.List is treated as invariant. So while a
Seq[Q[Int]] is a Seq[Q[_ <: Int]] since Int <: Int, a List[Q[Int]] is *not* a
List[Q[_ <: Int]]:
scala> val a4 = Q.fprime(qs2.asJava)
<console>:11: error: type mismatch;
found : java.util.List[Q[Int]]
required: java.util.List[Q[_]]
Note: Q[Int] <: Q[_], but Java-defined trait List is invariant in type E.
You may wish to investigate a wildcard type such as `_ <: Q[_]`. (SLS
3.2.10)
val a4 = Q.fprime(qs2.asJava)
^
I'm afraid I don't have an answer as to whether the Scala compiler should
be able to "introduce" the extra type variable S = _ <: T that is the
difference between fprime and fdoubleprime, and use it to solve the type
equation - would also be curious to learn more about that.
Regards
ap
--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [email protected].
For more options, visit https://groups.google.com/d/optout.