Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 664
worldterminator Avatar asked Feb 02 '17 18:02

worldterminator


People also ask

How to override or overload a method in Scala?

In Scala, method overriding uses override modifier in order to override a method defined in the super class whereas, method overloading does not requires any keyword or modifier, we just need to change, the order of the parameters used or the number of the parameters of the method or the data types of the parameters for method overloading.

How do you override a method in a subclass?

So, the overridden method can be called by creating the object of the subclass. Here, the constructor of the super-class i.e, Students is called from the primary constructor of the subclass i.e, newStudents so, the super-class constructor is called utilizing the keyword extends.

What is overriding in Java?

Overriding a method with a more specific type of argument is called overloading. It defines a method with the same name but with a different or more specific type of argument. An overloaded method is available besides the original method.

How to distinguish the methods with different method signatures in Scala?

Scala can distinguish the methods with different method signatures. i.e. the methods can have the same name but with different parameter list (i.e. the number of the parameters, the order of the parameters, and data types of the parameters) within the same class.


3 Answers

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 = ...
}
like image 148
puhlen Avatar answered Sep 24 '22 07:09

puhlen


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.

like image 37
Michael Zajac Avatar answered Sep 21 '22 07:09

Michael Zajac


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.

like image 20
WillD Avatar answered Sep 20 '22 07:09

WillD