Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala abstract class method that returns a new corresponding class child object

I have the following class in my mind:

abstract class MyClass (data: MyData) {

  def update(): MyClass = {
    new MyClass(process())
  }

  def process(): MyData = {
    ...
  }

}

However, abstract classes cannot be instantiated so the line new MyClass(process()) is an error. My question is - is there any way to tell the compiler that in case of each of the child classes of MyClass I want to create an object of exactly that child class? It seems an overkill to write this method awhole in all child classes. Playing with type parameters of the class or method I could not acheive that myself.

like image 656
noncom Avatar asked Jan 12 '12 13:01

noncom


People also ask

Can we create obj of abstract class?

We cannot create objects of an abstract class. To implement features of an abstract class, we inherit subclasses from it and create objects of the subclass. A subclass must override all abstract methods of an abstract class. However, if the subclass is declared abstract, it's not mandatory to override abstract methods.

Can abstract class be instantiated in Scala?

We can then declare the method abstract. Also, you cannot instantiate Scala abstract class. In simple words, you cannot create an object of it. A class can only inherit from one Scala abstract class.

What is abstract method in Scala?

Abstraction is the process to hide the internal details and showing only the functionality. In Scala, abstraction is achieved by using an abstract class. The working of the Scala abstract class is similar to Java abstract class. In Scala, an abstract class is constructed using the abstract keyword.

Can abstract class have return value?

An abstract method has no body. (It has no statements.) It declares an access modifier, return type, and method signature followed by a semicolon. A non-abstract child class inherits the abstract method and must define a non-abstract method that matches the abstract method.


2 Answers

How about something like this? MyClass is parametrized with the concrete type. Of course, all concrete classes have to implement a method that actually returns a new instance of Self.

trait MyClass[+Self <: MyClass[Self]] {
  def update(): Self = {
    makeNew(process())
  }

  def process(): MyData = {
    // ...
  }

  protected def makeNew(data: MyData): Self
}

class Concrete0 extends MyClass[Concrete0] {
  protected def makeNew(data: MyData) = new Concrete0
}

class RefinedConcrete0 extends Concrete0 with MyClass[RefinedConcrete0] {
  override protected def makeNew(data: MyData) = new RefinedConcrete0
}

Credit: IttayD’s second update to his answer to this question.

like image 76
Jean-Philippe Pellet Avatar answered Jan 03 '23 13:01

Jean-Philippe Pellet


To completly avoid implementing almost identical method in all subclasses you would need to use reflection. I guess that would be your last resort if you have chosen Scala. So here is how to minimize the repetitive code:

// additional parameter: a factory function
abstract class MyClass(data: MyData, makeNew: MyData => MyClass) {

  def update(): MyClass = {
    makeNew(process())
  }
  def process(): MyData = {
    ...
  }
}

class Concrete(data: MyData) extends MyClass(data, new Concrete(_))

This way you repeat only the shortest fragment required to instantiate the subclass.

like image 34
Przemek Pokrywka Avatar answered Jan 03 '23 13:01

Przemek Pokrywka