简体   繁体   中英

Scala override method with subclass as parameter type

I have a trait A which has a method def fun1( b:B ):C I want A 's subclass implement B with more detailed type:

Here is the code:

trait B
trait C

trait A {
  def fun1( b:B ):C
}

class B1 extends B{
}

class B2 extends B{
}


class C1 extends C{
}

class C2 extends C{
}

I hope A 's subclass can be declared as below

class X1 extends A{
    override def fun1(b:B1):C1 = ...
}


class X2 extends A{
    override def fun1(b:B2):C2 = ...
}

However, the compiler will complain that X1 overrides nothing . I have to manually match detailed B 's type, like below.

class X1 extends A{
    override def fun1(b:B):C = b match {case x:B1 => ... }
}


class X2 extends A{
    override def fun1(b:B2):C2 = b match {case x:B2 => ... }
}

This method cannot check the correct type during compiling. How can I achieve the first implementation? Is there any design pattern to handle this problem?

A similar question is C# Override method with subclass parameter

You can do this with a generic type parameter.

trait A[T <: B] {
   def fun1( t:T ):C
}

class X1 extends A[B1]{
    override def fun1(b:B1):C1 = ...
}

You cannot refine the parameter types of an inherited method, because methods/functions are contravariant over them.

Consider this simplified example:

trait A {
    def foo(b: Animal): Unit
}

trait Animal
class Cat extends Animal
class Dog extends Animal


class X1 extends A {
    def foo(b: Cat): Unit
}

class X2 extends A {
    def foo(b: Dog): Unit
} 

val list: List[A] = List(new X1, new X2)

This doesn't compile, but let's pretend it does for a moment. If we need to iterate through the list and pass an Animal to each instance via foo , what happens? X1 is supposed to be able to handle any Animal , but instead it only accepts a Cat , what would happen when passing a Dog , instead? You're asking X1 to break its contract with A .

You can't override to a more specific type. You can overload (removing the override), when creates an additional method for the more specific type. The most specific method will be called based on the actual param passed.

class X1 extends A{
  def fun1(b:B1):C1 = ...
}

In this case, passing a B1 executes the fun1 in X1, passing any other B executes the fun1 in A.

Allowing this type of override would essentially prevent X1 from taking a B as a parameter, only accepting a B1. This is in direct conflict with the method declared and defined by Trait A and can't override it. If the override was allowed, then x1.fun1(b:B) is indeterminate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM