Scala: Extend concrete class with constructor parameters

10,417

Solution 1

If I understand correctly you want the name and surname fields in Son to be immutable, as opposed to those in Person, which are vars.

That simply isn't possible. The only way to do it would be by overwriting:

class Person (var name: String, var surname: String)

//this won't compile
class Son(override val name: String, override val surname: String) extends Person(name, surname)

In Scala you cannot overwrite a var with a val - and it is pretty obvious why - subclasses can only override or add functionality to a superclass. If we wore to allow vals to override vars we would remove from the parent class the setter for the overridden field. This breaks the "is-a" relationship implied by inheritance.

What you could do is implement this like so:

trait Person {
    def name: String
    def surname: String
}

//this is fine now
class Son(val name: String, val surname: String) extends Person

//in case you want a type of person which can be changed.
class MutablePerson(var name: String, var surname: String) extends Person

Person now is a trait - it just provides a way of getting the name or surname. Son overrides Person by using vals - and thus you get the guarantee that nobody will change the fields in Son ever again.

From your example I assume that you still want to have a type of Person that can be modified. And you can do that using the MutablePerson class above, which does allow it's fields to be mutated.

Hope this helps !

Solution 2

You have to name the params different, because otherwise the methods in the body of son will try to access the params and not the fields in the Person class. Scala will automatically create fields for the params if you access them in the body. It will work, when you do something like this (which also is a commonly used pattern):

class Son (_name: String, _surname: String) extends Person(_name, _surname){
  def printSon = {
  if(name == "name")println("Error name Person")
  if(surname == "surname")println("Error surname Person")
  }
}
Share:
10,417
user1826663
Author by

user1826663

Updated on June 09, 2022

Comments

  • user1826663
    user1826663 almost 2 years

    I have this concrete class:

    class Person (var name: String, var surname: String)
    

    and I want to create another class that extends Person:

    class Son (name: String, surname: String) extends Person(name, surname)
    

    OK. But I do want the fields in the constructor of Son must be var and not val. How do I fix this? The fields must remain constructor parameters.

    UPDATE #2

    My problem is as follows: If I define a method in Son, this does not work if I change the value to the parameters of an instance of Son.

    class Son (name: String, surname: String) extends Person(name, surname){
      def printSon = {
      if(this.name=="name")println("Error name Person")
      if(this.surname=="surname")println("Error surname Person")
      }
    }
    
    object main {
      def main(args: Array[String]): Unit = {}
    
      val Marco = new Son("Marco","Bianchi")
      Marco.printSon // So far everything is ok
      Marco.name="name"
      Marco.printSon // Here in control is not done, because Marco.name="name" writes in Person
      println("FINE")
    }
    

    name e surname in Son are of type val.