Reputation:
My question is how does the last println(salt.value())
print a value of 5.0. I thought that the statement crystal.grow()
would add 1 to the salt value of 6 and the statement salt.value()
would multiply 7 by 0.5 which then give the answer 3.5. What am I missing here?
abstract class Crystal(var size: Double) {
def value(): Double
def grow(): Unit = {
this.size += 1.0
}
}
class Quartz(quartzSize: Double) extends Crystal(quartzSize) {
override def value(): Double = {
this.size * 5.0
}
}
class Salt(saltSize: Double) extends Crystal(saltSize) {
override def value(): Double = {
this.size * 0.5
}
override def grow(): Unit = {
this.size += 4.0
}
}
object Part1 {
def main(args: Array[String]): Unit = {
val quartz: Quartz = new Quartz(5.0)
val salt: Salt = new Salt(6.0)
val crystal: Crystal = salt
crystal.grow()
println(salt.value())
}
}
Output:
5.0
Upvotes: 0
Views: 80
Reputation: 1509
Using types you essentially give the compiler hints to check your code. So by saying val crystal: Crystal = salt
, you just tell it to treat crystal
as the less-specific class Crystal
from now on (i.e., formally check your code only considering this).
You do not change the actual object in this case though (even more so because you cannot have instances of an abstract class, which Crystal
is). So if you say crystal.grow()
, the interpreter will still look for the most specific version of grow()
that it can find, in this case the overridden one in Salt
. You can check this with getClass
:
scala> salt.getClass
res1: Class[_ <: Salt] = class Salt
scala> crystal.getClass
res2: Class[_ <: Crystal] = class Salt
As for why crystal
and salt
point to the same object. Scala/Java only make copies for primitive types (e.g., Int or Double; like many other languages), i.e., for objects we simply create a pointer to the same object.
Upvotes: 0
Reputation: 928
It's all because you have override grow() method in the salt class. Please find explaination as below.
With override grow() in the Salt :
abstract class Crystal(var size: Double) {
def value(): Double
def grow(): Unit = {
println("Cystal.value = " + this.size)
this.size += 1.0
}
}
class Quartz(quartzSize: Double) extends Crystal(quartzSize) {
println("quartzSize = " + quartzSize) // Size = 5.0
override def value(): Double = {
println("Quartz.value = " + this.size) // Size = 5.0
this.size * 5.0
}
}
class Salt(saltSize: Double) extends Crystal(saltSize) {
println("saltSize = " + saltSize) // Size = 6.0
override def value(): Double = {
println("Salt.value = " + this.size) // Size = 10
this.size * 0.5 // size = 5.0
}
override def grow(): Unit = {
println("Salt.grow() = " +this.size) // Size = 6.0
this.size += 4.0 // Size = 6.0 + 4.0
}
}
object Test extends App {
val quartz: Quartz = new Quartz(5.0) // You have set Size = 5.0
val salt: Salt = new Salt(6.0) // You have set Size = 6.0
val crystal: Crystal = salt // size = 6.0 (saltSize)
println("Test - crystal.grow() =" + crystal.grow()) // Size = 10.0 -- It calls the Salt.grow method as you have override the grow method.
println("Test - salt.value() =" +salt.value()) // size = 5.0
println("Test - quartz.value() ="+quartz.value()) // size = 25
}
Output:
quartzSize = 5.0
saltSize = 6.0
Salt.grow() = 6.0
Test - crystal.grow() =()
Salt.value = 10.0
Test - salt.value() =5.0
Quartz.value = 5.0
Test - quartz.value() =25.0
Without overriding grow() in the Salt :
abstract class Crystal(var size: Double) {
def value(): Double
def grow(): Unit = {
println("Cystal.value = " + this.size) // 6.0
this.size += 1.0 // size = 7.0
}
}
class Quartz(quartzSize: Double) extends Crystal(quartzSize) {
println("quartzSize = " + quartzSize) // Size = 5.0
override def value(): Double = {
println("Quartz.value = " + this.size) // Size = 5.0
this.size * 5.0
}
}
class Salt(saltSize: Double) extends Crystal(saltSize) {
println("saltSize = " + saltSize) // Size = 6.0
override def value(): Double = {
println("Salt.value = " + this.size) // Size = 10
this.size * 0.5 // size = 5.0
}
//override def grow(): Unit = {
// println(this.size) // Size = 6.0
// this.size += 4.0 // Size = 6.0 + 4.0
//}
}
object Test extends App {
val quartz: Quartz = new Quartz(5.0) // You have set Size = 5.0
val salt: Salt = new Salt(6.0) // You have set Size = 6.0
val crystal: Crystal = salt // size = 6.0 (saltSize)
println("Test - crystal.grow() =" + crystal.grow()) // Size = 7.0 -- It calls the Cystal.grow method as we are not overriden the grow method.
println("Test - salt.value() =" +salt.value()) // size = 3.5
println("Test - quartz.value() ="+quartz.value()) // size = 25
}
Output :
quartzSize = 5.0
saltSize = 6.0
Cystal.value = 6.0
Test - crystal.grow() =()
Salt.value = 7.0
Test - salt.value() =3.5
Quartz.value = 5.0
Test - quartz.value() =25.0
Hope it helps!
Upvotes: 1