Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala: abstract class constructor parameter vs Trait val members?

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!

like image 698
Kane Avatar asked Dec 11 '12 21:12

Kane


People also ask

What is difference between abstract class and trait in Scala?

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.

Can abstract class have constructor in Scala?

Scala traits don't allow constructor parameters However, be aware that a class can extend only one abstract class.

Can traits have constructors Scala?

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.

Can an abstract class extend a trait Scala?

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.


1 Answers

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.)

like image 150
som-snytt Avatar answered Sep 26 '22 04:09

som-snytt