Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java/Scala Bounded Generics and type inference mismatch

Coming from a Java background, I understand that this does not compile.

public static class SuperClass {}
public static class SubClass extends SuperClass {}

public static <T, U extends T> U returnSub(T sup, U sub) {
    return sub;
}

public static void main(String[] args) {
    SuperClass parent = new SuperClass();
    SubClass child = new SubClass();

    returnSub(parent, child);
    returnSub(child, parent); // Java doesn't like that
}

The last line produces a compiler error (EDIT : at least on jdk1.6.0_65) it does :

Bound mismatch: The generic method returnSub(T, U) of type Test is not applicable for the arguments (Test.SubClass, Test.SuperClass). The inferred type Test.SuperClass is not a valid substitute for the bounded parameter

So, I got surprised, that this seems to work in Scala. I wrote the sample code below (which as far as I can tell, expresses the same "logic") :

class SuperClass
class SubClass extends SuperClass

def returnSub[Type, SubType <: Type](supArg: Type, subArg: SubType): SubType = {
  subArg
}

override def main(args: Array[String]): Unit = {
  val parent = new SuperClass()
  val child = new SubClass()

  val iAmOkWithThat: SubClass = returnSub(parent, child)
  val iDontGetThat: SuperClass = returnSub(child, parent)
}

I guess the Scala compiler is smart enough to say "OK, child is an instance of SubClass, but I can't invoke returnSub if I say that, so let me try if I consider child as a SuperClass instance, and, well, it works, so let's do that".

Is that what's going on (and if so, can you point to a language specification about that) ? Or maybe my Scala "conversion" is not equivalent to my Java code ?

Thanks!

like image 586
GPI Avatar asked Oct 30 '22 18:10

GPI


1 Answers

Your code should work for both languages because T and U can both be SuperClass. With Java 1.8 your code compiles without problems. Type inference has improved greatly since generics were introduced, but you can get this to work on all versions of Java from 1.5 onwards by writing

ThisClass.<SuperClass, SuperClass>returnSub(child, parent);

You need to provide explicit type arguments like this much less frequently now.

As for why you don't get the same issues with Scala, I'm afraid I can't answer that as I'm don't know Scala at all.

like image 199
Paul Boddington Avatar answered Nov 02 '22 11:11

Paul Boddington