I want to define a constructor in an abstract class that will create concrete 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? Is this even possible to implement?
EDIT: Clarification: I want to abstract over the construct method. I do not want to call separately new B
and new C
from either subclasses or companion objects.
You can use reflection to create a new instance. Something like this would work but in my opinion is not worth the trouble. For one thing you would only be able to check if a suitable constructor existed at runtime.
You need to explicitly invoke a constructor if you want create a new instance.
Scala erases type at runtime so there is no way to know what Impl meant when the class was created.
You would put the constructor in the companion object, not in the abstract class. Like this:
Now, you could create an instance of
A
by callingA(42)
, orA("foobar")
, for example. The string and integer parameters are only examples, of course. If the parameters for all the constructors have the same types, this overloading will not work. In that case, you can easily create different methods and call them something other thanapply
.Looks like this is not possible. According to the Scala book (by Oderski, Spoon, Venners) you cannot create an instance of an abstract type. See: Abstract Types chapter, Currencies case study. This may be supported later with "virtual classes".
Following my comment left at
Monkey
response. One way how to solve this is to use the Curiously Recurring Template Pattern (CRTP) together with a self types:Perhaps there is a better solution, but this is so far what I found.
I propose the following pattern:
All reduandancy you have now is precisely one line per subclass. I consider this a small price to pay for a) a working solution that b) does not use reflection (which breaks essentially all guarantees a static type system offers you).
I am still curious why you would need
construct
insideA
. Smells fishy.