Reputation: 3120
My question is about scala inheritance details. I have the following code.
package scalasandbox
object Main {
def main(args: Array[String]): Unit = {
val creature: Creature = new Human("First")
creature.rename("Second")
creature.introduce
}
}
class Creature(var name: String) {
def introduce = println("I'm creature: " + name)
def rename(newName: String) = {
println("Creature was renamed to: " + newName)
name = newName
}
}
class Human(name: String) extends Creature(name) {
override def introduce = println("I'm Human: " + name)
}
which produces the following output
Creature was renamed to: Second
I'm human: First
I expect it to be "I'm human: Second" because rename method should change the field value. I have opened Human class with decompiler:
package scalasandbox;
import scala.Predef.;
import scala.ScalaObject;
import scala.collection.mutable.StringBuilder;
import scala.reflect.ScalaSignature;
@ScalaSignature(bytes="\006\001\0212A!\001\002\001\013\t)\001*^7b]*\t1!\001\007tG\006d\027m]1oI\n|\007p\001\001\024\007\0011!\002\005\002\b\0215\t!!\003\002\n\005\tA1I]3biV\024X\r\005\002\f\0355\tABC\001\016\003\025\0318-\0317b\023\tyABA\006TG\006d\027m\0242kK\016$\b\002C\t\001\005\003\005\013\021\002\n\002\t9\fW.\032\t\003'Yq!a\003\013\n\005Ua\021A\002)sK\022,g-\003\002\0301\t11\013\036:j]\036T!!\006\007\t\013i\001A\021A\016\002\rqJg.\033;?)\taR\004\005\002\b\001!)\021#\007a\001%!)q\004\001C!A\005I\021N\034;s_\022,8-Z\013\002CA\0211BI\005\003G1\021A!\0268ji\002")
public class Human extends Creature
implements ScalaObject
{
private final String name;
public void introduce()
{
Predef..MODULE$.println(new StringBuilder().append("I'm Human: ").append(this.name).toString());
}
public Human(String name)
{
super(name);
}
}
and see "private final String name;" there. I think it hides Creature name field. And
Predef..MODULE$.println(new StringBuilder().append("I'm Human: ").append(this.name).toString());
this stuff looks also suspicious because of "this.name" instead of method call "this.name()". Could anyone explain where is my mistake and what is the correct way of implementing those two classes?
Upvotes: 4
Views: 341
Reputation: 49705
If Creature
is only intended for subclassing, I'd advise that you make both the class and the name
parameter abstract, as per my answer here:
Idiomatic Scala way to deal with base vs derived class field names?
One advantage to such a technique is that it then becomes far easier to use case classes for the specific, concrete, sub-classes
Upvotes: 2
Reputation: 6114
try by changing this line:
class Human(foo: String) extends Creature(foo) {
so you don't hide name
.
Upvotes: 3
Reputation: 59994
The name
variable that you use in the Human
class resolves to the constructor parameter of Human
, and Scala will automatically create private vals for constructor parameters that you use outside the constructor. This is unfortunate in your case. You can prevent this e.g. by naming your parameter in Human
differently, e.g. nm
:
class Human(nm: String) extends Creature(nm)
Upvotes: 4