user11206209
user11206209

Reputation:

Trouble understanding how class works in Scala

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

Answers (2)

Dominik Bucher
Dominik Bucher

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

KZapagol
KZapagol

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

Related Questions