javascalagenericsscala-java-interopf-bounded-polymorphism

Pass subclass of class as type parameter (type parameter is subclass)


let's consider:

public class Text extends BinaryComparable
    implements WritableComparable<BinaryComparable> {

We can see that Text is BinaryComparable.

Then, let's consider

@InterfaceAudience.Public
@InterfaceStability.Stable
public interface WritableComparable<T> extends Writable, Comparable<T> {

I have some class in Scala:

trait MyClass[A <: WritableComparable[A]] {

It is not possible to create

MyClass[Text] = new MyClass[Text]()

due to type mismatch. Why? After all, Text is BinaryComparable How to resolve it?


Solution

  • You can try to add one more type parameter

    trait MyClass[B >: A, A <: WritableComparable[B]]
    
    val mc: MyClass[BinaryComparable, Text] = new MyClass[BinaryComparable, Text] {}
    

    On contrary to trait MyClass[A <: WritableComparable[_ >: A]] this doesn't produce illegal cyclic reference.

    Alternatively you can define bounds in MyClass as

    trait MyClass[B, A <: B with WritableComparable[B]]
    
    val mc: MyClass[BinaryComparable, Text] = new MyClass[BinaryComparable, Text] {}
    

    You can even exclude B with existential type (as @user proposed)

    trait MyClass[A <: B with WritableComparable[B] forSome { type B }]
    
    val mc: MyClass[Text] = new MyClass[Text] {}
    

    Such existential types will be deprecated in Scala 3

    http://dotty.epfl.ch/docs/reference/dropped-features/existential-types.html