I notice that there were several discussions about how to choose between abstract classes and traits, but it seems that none of them focused on the following point. One reason that made me use abstract classes is, they can have constructor parameters, while traits cannot. But why not the following
trait X {
def haha: Int
}
class Y(val haha: Int) extends X
and early definition is even not necessary to get everything work properly (which I worried about). The abstract class version is
abstract class X(haha: Int)
class Y(val haha: Int) extends X(haha)
and I don't like the abstract class version because, when you extend several times, these constructor parameters appear everywhere (maybe someone tells me how to avoid this?).
I am aware that abstract classes interpolate with Java better, and match the "is-a" concept more. Despite these, is there any reason that I should use abstract classes somewhere? Thanks!
The first difference was already mentioned: classes are limited to inherit from a single abstract class but can inherit from multiple traits. Another important difference is that abstract classes allow specifying constructor parameters. Traits do not allow us to do the same.
Scala traits don't allow constructor parameters However, be aware that a class can extend only one abstract class.
Traits are used to define object types by specifying the signature of the supported methods. Scala also allows traits to be partially implemented but traits may not have constructor parameters.
Discussion. Although Scala has abstract classes, it's much more common to use traits than abstract classes to implement base behavior. A class can extend only one abstract class, but it can implement multiple traits, so using traits is more flexible.
The class parameter does not have to be a member (field or def).
abstract class X(haha: Int) {
val hoho = 2 * haha // compile-time constant
}
Similarly, trait initialization order depends on linearization (mix-in order), which is why trait members should be defs and not vals. (And you can always override the def with a val.) With an abstract class, you know who your supers are, and you're defining extension points for subclasses.
But note your abstract class has the val in the wrong place:
abstract class X(val haha: Int)
class Y(haha: Int) extends X(haha)
That is, you would expect X to decide if the param is a val (and it doesn't have to be). Usage of the param in either X or Y could turn it into a field.
Your observation about value params for classes also applies to type params: What a nuisance to pass Foo[A] up the hierarchy. So in Scala, we can have a member type A instead that can remain abstract until defined in a leaf. But this doesn't actually bear on whether to define a trait or a class.
But trait parameters are coming to Scala. (See the Scala bugs for early definitions which are low-priority for this reason.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With