Search code examples
scalatype-parametergeneric-type-argument

How to make scala type parameter inference smarter?


I have a function that takes a type parameter T that has to be a subtype of this.type:

def injectFrom[T <: this.type](same: T): Unit = ...

however every time I use it, the compiler gave me a

type T cannot be inferred" error

and every time it can be fixed by specifying T explicitly as (instance_variable).type. How can I avoid doing this in the future?


Solution

  • this.type is a type of an individual object or class instance, not of the class.

    In the following code a1 and a2 will have different this.type:

    class A
    val a1 = new A()
    val a2 = new A()
    

    So type parameter [T <: this.type] doesn't really make sense as you can't extend an object or an instance.

    If you want to have a design, so that functions in subclasses can accept only instances of that subclass (and consequently instances of subclasses only of that subclass) you would have to make the type explicit by using type parameter or type variable:

    trait A {
        type Self
        def injectFrom(same: Self): Unit = ???
    }
    class B extends A {
        type Self = B
    }
    class C extends A {
        type Self = C
    }
    

    or something that Scala does for example in Ordered implementation:

    trait A[Self] {
        def injectFrom(same: Self): Unit = ???
    }
    class B extends A[B]
    class C extends A[C]
    

    In both cases new B().injectFrom(new B()) will compile but new B().injectFrom(new C()) won't.

    The modification of the second example that allows you to have this injectFrom this inside A:

    trait A[Self] {
        def injectFrom(same: A[Self]): Unit = ???
        def test() {
            this injectFrom this
        }
    }