1

How is it possible to make this code work?

As far as I know, Scala doesn't have dynamic dispatch (similar to Java). Is it possible to simulate dynamic dispatching somehow?

Or what's the best solution?

object Tezt {

  case class SuperClazz()
  case class SubClazz1() extends SuperClazz
  case class SubClazz2() extends SuperClazz

  def method(obj: SubClazz1) = {
    // stuff
  }

  def method(obj: SubClazz2) = {
    // stuff
  }

  def func[T <: SuperClazz](obj: T) = {
    Tezt.method(obj) // Error: Cannot resolve method reference with such signature
  }
}
pedrorijo91
  • 7,635
  • 9
  • 44
  • 82
  • java wouldn't allow this either. Your code is simply wrong. Try explaining what you are trying to do in words. – Dima Feb 27 '16 at 00:18
  • I said Java doesn't have also. I have a function that receives an object, that is a subclass of `SuperClazz` and there are 2 methods, onde for each subclass. How do I know which to find? – pedrorijo91 Feb 27 '16 at 00:26
  • Suppose, it was allowed. If you pass in an instance of Subclazz3, then what? – Dima Feb 27 '16 at 00:30

1 Answers1

5

The standard way to implement dynamic dispatch on a single argument is object-oriented polymorphism:

abstract class SuperClazz() {
  def method(): ReturnType
}
case class SubClazz1() extends SuperClazz {
  def method() = {
    // stuff
  }
}
case class SubClazz2() extends SuperClazz {
  def method() = {
    // stuff
  }
}

// Alternatively just `def func(obj: SuperClazz) =` in this case
def func[T <: SuperClazz](obj: T) = 
  obj.method()

Mind that you can't extend a case class with another case class, and it's usually considered bad style to extend case classes at all. To implement this you'd probably need method to be abstract in SuperClazz, and thus SuperClazz should be a trait or an abstract class.

Another common alternative for dynamic dispatch in scala is a pattern match:

sealed abstract class SuperClazz()
case class SubClazz1() extends SuperClazz
case class SubClazz2() extends SuperClazz

def method(obj: SubClazz1) = {
  // stuff
}

def method(obj: SubClazz2) = {
  // stuff
}

def func(obj: SuperClazz) =
  obj match {
    case sc1: SubClazz1 => method(sc1)
    case sc2: SubClazz2 => method(sc2)
  }

It's common to implement pattern matches like this when the super class or trait is sealed (in this case sealed abstract class SuperClazz()). When matching on objects of sealed super classes, the compiler will check that you have listed every possibility in the match, to ensure there won't be a runtime error when matching. The compiler will give you a warning if you forget to specify some possibilities.

Pattern matches also work for multiple argument dynamic dispatch, but compared to polymorphism, they usually require writing more boilerplate code and may have a greater runtime performance cost for linearly testing every match case and calling unapply functions.

Community
  • 1
  • 1
Kolmar
  • 14,086
  • 1
  • 22
  • 25
  • side note: I can't extend a case class from another case class? Not sure, but I'm not getting any error doing that. btw, why is considered bad practice to extend case classes? – pedrorijo91 Feb 27 '16 at 00:29
  • 1
    @pedrorijo91 case class to case class inheritance has been prohibited since scala version 2.9. Did you try to compile some code with such inheritance? IDE may not be giving an error, but it still won't compile in modern scala versions. – Kolmar Feb 27 '16 at 02:39
  • 1
    @pedrorijo91 As for inheriting a normal class from a case class, it's often just meaningless. All automatic case class methods will still be provided by the parent case class. E.g., calling `copy` method on a child returns an instance of the parent case class. Unoverridden `equals` and `hashCode` consider only fields that exist in the parent case class. And there is no automatic companion object with `apply`/`unapply` for the child. The usual way is to have some hierarchy of traits and abstract classes, and make only the leaves in this inheritance hierarchy be `case class`es. – Kolmar Feb 27 '16 at 02:47