I have the following sophisticated type hierarchy in Java:
// the first type
interface Element<Type extends Element<Type>> {
Type foo(Type a, Type b);
}
// the second type
interface Payload<Type extends Payload<Type>> {
Type bar(Type[] array);
}
// some toy implementation
final class SomePayload implements Payload<SomePayload> {
@Override
public SomePayload bar(SomePayload[] array) { return array[0]; }
}
// mix of first and second interfaces
interface ComplicatedElement<
PayloadT extends Payload<PayloadT>,
ObjectT extends ComplicatedElement<PayloadT, ObjectT>>
extends Element<ObjectT> {
PayloadT getPayload();
ObjectT add(ObjectT a, ObjectT b);
}
// some toy implementation
final class SomeComplicatedElement
implements ComplicatedElement<SomePayload, SomeComplicatedElement> {
final SomePayload data;
public SomeComplicatedElement(SomePayload data) {
this.data = data;
}
@Override
public SomePayload getPayload(){ return data; }
@Override
public SomeComplicatedElement foo(SomeComplicatedElement a, SomeComplicatedElement b) {
return b;
}
@Override
public SomeComplicatedElement add(SomeComplicatedElement a, SomeComplicatedElement b) {
return a;
}
}
I have some static method which deals with ComplicatedElement
s:
public static <PayloadT extends Payload<PayloadT>,
ObjectT extends ComplicatedElement<PayloadT, ObjectT>>
List<ObjectT> method(ObjectT input) {
return Collections.singletonList(input);
}
Now, from Java I can call method
without problems like this:
public static void main(String[] args) {
System.out.println(method(new SomeComplicatedElement(new SomePayload())));
}
However, when I try to do the same thing in Scala:
import FooBarJava.{SomeComplicatedElement, SomePayload, method}
def main(args: Array[String]): Unit = {
println(method(new SomeComplicatedElement(new SomePayload())))
}
I have this compilation error:
Error:(10, 21) inferred type arguments [Nothing,FooJava.SomeComplicatedElement] do not conform to method method's type parameter bounds [PayloadT <: FooJava.Payload[PayloadT],ObjectT <: FooJava.ComplicatedElement[PayloadT,ObjectT]]
println(FooJava.method(new SomeComplicatedElement(new SomePayload())))
I can fix this by specifying type parameters explicitly:
println(method[SomePayload, SomeComplicatedElement](new SomeComplicatedElement(new SomePayload())))
But it is very annoying and I would like to avoid this (I guess it is possible since Java compiler just work fine with this). Is there any way to do so?
(I guess it is possible since Java compiler just work fine with this)
Scala has richer type system than Java. For example in Java there is no type similar to Nothing
in Scala (i.e. universal subtype). So it's possible that sometimes compiler in a language with richer type system will be unable to infer types while in similar situation compiler in a language with poorer type system can do this.
If specifying type parameters is too annoying why not to create some helper method?
private def methodWithPayload(data: SomePayload): java.util.List[SomeComplicatedElement] =
method[SomePayload, SomeComplicatedElement](new SomeComplicatedElement(data))
methodWithPayload(new SomePayload)
In Java there is the only option <SomePayload, SomeComplicatedElement>method(..)
, in Scala there are two options method[SomePayload, SomeComplicatedElement](..)
and method[Nothing, SomeComplicatedElement](..)
and both options are valid.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With