5
votes

In Scala, how can I extend a trait in a class with private constructor parameter that is defined in the trait?

trait Parent {
  protected def name: String
  require(name != "", "wooo problem!")
}

class Child(private val name: String) extends Parent {
  println("name is " + name)
}

The above class gives an error:

class Child needs to be abstract, since method name in trait Parent of type ⇒ String is not defined.

Of-course I can:

  1. make the Child class abstract,
  2. define it without using the private in the constructor like class Child(val name: String).
  3. make the Parent an abstract class instead of a trait

But with the above implementation, is there no way I can have a private constructor parameter while extending a trait? Note that I want the variable to be private so that I should not be able to do childInstance.name.

2
What are you trying to achieve with this? Why do you need a constructor with a private variable? Can't you just define the private variable in the class and have an empty constructor?nmat
Since this class is being extended by several children, I don't want to repeat the code. I think I found a way though. If I make the variable in the trait protected and change the child constructor to Child(name: String), I cannot access the variable outside. This is good enough for me!rgamber
Why don't you just define class Child{ private val name = "" } ?nmat
That is because I have some method signatures in the trait that I want all the children to define. So a trait makes more sense in my opinion! Let me know if I am wrong. Sorry I should have mentioned that in the question.rgamber

2 Answers

2
votes

Try this

  trait Parent {
    protected def name: String
    require(name != "", "wooo problem!")
  }

  class Child(override protected val name: String) extends Parent {
    val publicVar = "Hello World"
    println("name is " + name)
  }

  def main(args: Array[String]): Unit = {
    val child = new Child("John Doe")
    println(child.publicVar)
    println(child.name) // Does not compile
  }

You will not be able to access to child.name

1
votes

If you have an abstract method in a trait, then all the derived classes need to have the same (or more permissive) modifier (in your case at least protected) for the abstract methods.

trait Parent {
  protected def name: String
  require(name != "", "wooo problem!")
}

class Child(private val privateName: String) extends Parent {
  override protected def name: String = privateName
  println("name is " + name)
}

You can keep your constructor private, but you need to define the override protected def name: String and make use of the private value of your constructor.