2

Why does subclass create a copy of field when inheriting using a primary constructor?

For example

object Question
{
  class Animal(var name : String) {

    def setName(name : String) {
      this.name = name
    }
  }

  class Dog(name : String) extends Animal(name) {
    this.setName("dog: " + name)

    override def toString: String = this.name // this actually returns "Billy"
  }

  def main(args: Array[String]) {
    val dog = new Dog("Billy")
    println(dog.toString) // output "Billy", why?
    println(dog.name) // output "dog: Billy", why?
  }
}

As you can see, dog.toString() returns "Billy" instead of "dog: Billy", does it mean this.name is different from inherited name ? If so, then why does dog.name return "dog: Billy" ?

2 Answers 2

5

If you run your compiler with the -Xlint option you should see the following.

warning: private[this] value name in class Dog shadows mutable name inherited from class Animal. Changes to name will not be visible within class Dog - you may want to give them distinct names.

If you rename the name argument to the Dog class, the warning goes away and the output is more consistent and perhaps closer to what's expected.

Sign up to request clarification or add additional context in comments.

4 Comments

Ok. So primary constructor will create fields for whatever parameters passed in, isn't that a waste of resource if all I want is passing them to super class's constructor?
I know that fact for a long time. And never stop wondering why there is no way to specify constructor argument without creating private[this] field behind the scene
"isn't that a waste of resource if all I want is passing them to super class's constructor" But you don't: you use it in toString. That's why the compiler has to store it in a field. If you don't use the argument outside the constructor, no field should be created.
@ayvango There is: just don't use the constructor argument outside the constructor. What there is not is a way to tell the compiler to make sure you don't use it accidentally (like there is with @tailRec or @switch).
0

Here's your code debug result

your code debug result.

So, what you can see is that there are really actually two instances of variable "name". One is from "Animal", and one from "Dog". Constructors work a little bit different in Scala - what you call constructor arguments are actually local variables that are initialized with constructor arguments. I can't really provide any elegant solution to this, unfortunately. Also, I might be wrong. Please correct me if I am.

Update

Try this question.

3 Comments

It looks to me those constructor arguments are actually fields, since this.name returns "Billy".
@taffykula, well, they are, actually. If you add var to Dog.name, you should get an error because of a name clash, see that post down bellow my answer for further explanations. So you should basically deal with how any constructor parameter is going to be a variable because this is how Scala ideology is. You could probably deal with this by renaming Dog.name to something else and assigning this value to Animal.name. After that just use Animal.name only.
It doesn't look like I can edit the old comment. By saying "a local variable", I mean "a variable in scope of an instance" e.g. "a field", basically.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.