Subclassing from a base abstract class

I want to define a constructor in an abstract class that will create specific subclasses.

abstract class A {
  type Impl <: A
  def construct() : Impl = {
    val res = new Impl() //compile error: class type required but A.this.Impl found
    // do more initialization with res
  }
}

class B extends A {type Impl = B}
class C extends A {type Impl = C}
//...
val b = new B
b.construct() // this should create a new instance of B

What is wrong here? Can this be implemented? The EDIT: . Explanation: I want to abstract using the construction method. I do not want to cause separate new Band new Csubclasses or associated facilities.

+3
source share
6 answers

You need to explicitly call the constructor if you want to create a new instance.

abstract class A {

  def newInstance(): this.type;

  def construct() : this.type = {
    val res = newInstance()
  }
}

class B extends A {
  def newInstance() = new B()
}

Scala erases the type at runtime, so there is no way to find out what Impl meant when creating the class.

+2
source

You put the constructor in a companion object, not in an abstract class. Like this:

object A {
  def apply(i:Int):A = new B(...)
  def apply(s:String):A = new C(...)
}

A, , , A(42) A("foobar"). - , , . , . - , apply.

+1

. - , , , . -, , .

def newInstance[T:ClassManifest]:T = {
  val klass = implicitly[ClassManifest[T]].erasure
  val constr = klass.getConstructors()(0)
  constr.newInstance().asInstanceOf[T]
}

abstract class A {
  def construct(implicit cm:ClassManifest[this.type]): this.type = {
    val res = newInstance[this.type]
    res
  }
}

class B extends A
+1

, . Scala (Oderski, Spoon, Venners) . . " ", . " ".

0

:

abstract class A($params) {
  // do common initialisation here
  def construct() : A

  def foo(...) = {
    ...
    val bar = construct()
    ...
  }
}

class B($moreparams) extends A($someparams) {
  // do special initialisation here
  def construct() = new B()
}

, , . , ) , ) (, , , ).

, construct A. .

0

Following my comment, I remained in the answer Monkey. One way to solve this problem is to use the Curiously Recurring Template Pattern (CRTP) along with self types:

abstract class A[T <: A[T]] { this: T =>

  def newInstance(): T;

  def construct(): T = {
    val res = newInstance()
    res
  }

  def some(): T = this
}

class B extends A[B] {
  def newInstance() = new B()
}

There may be a better solution, but so far I have found.

0
source

Source: https://habr.com/ru/post/1788908/


All Articles