3
votes

Is it possible to override vals or defs in the subclass's constructor? I want to initialize (or set) trait's members or abstract class's members in the subclass's constructor as parameters.

The following is an example.

trait A {
  def memberDef: Int => String
  val memberVal: String
}

class B(
    override val memberDef: Int => String,
    override val memberVal: String)
  extends A {
  ...
}

Here, class B's memberDef overrides trait A's memberDef, and class B's memberVal overrides trait A's memberVal.

When I compiled this, there was no error. However, I want to know whether there are any bugs in this implementation, or whther there is a better implementation.

2

2 Answers

3
votes

The answer to the title of the post is yes. For the most part.

It is hard to say what might be a "better" implementation since I don't know what you are trying to accomplish with this code (besides a proof of concept). But there are two things to consider.

You don't generally want a trait with a val in it. There are tricky, well-documented initialization problems solved only by using lazy val or def at the trait level. Also, while def in a trait can be implemented by a def, val, lazy val or object, val in a trait can only be implemented by val. So there is a lot less flexibility there.

The other thing to consider is less about Scala syntax but more general object design. I know your example is contrived, but just keep in mind you have created a leaky abstraction by giving the caller a way of altering the public API of B. Leaky abstractions are never good.

5
votes

I would like to add one more possible solution using early initializers:

class B(memberDefParam: Int => String, memberValParam: String) extends {
  val memberVal: String = memberValParam
} with A {
  val memberDef: Int => String = memberDefParam
}

I would use this because Martin Odersky said that if you use early initializers you have achieved the holy grail - Level L3: Expert library designer: http://www.scala-lang.org/old/node/8610

By the way overriding a public method by a function provided as a constructor argument doesn't look nice to me at all, but that's another story.