0
votes

I have created a trait called Animal and two classes, Dog and Cat. Both Dog and Cat have companion classes that store the number of lives they have. My Cat object has 9 lives and my Dog object has 1 life. I want to add a function to the Animal trait called isAlive and implement there. The isAlive function needs access to the number of live the Animal has. How would I get access to the lives value in the companion classes?

Should I just move the lives value into the Class and remove the companion classes?

Here's my code.

The trait

package Animal

trait Animal {

  def speak: String

  def getDeaths: Int

  def isAlive: Boolean = {
    getDeaths < 1 // I want to replace 1 with the number of lives from the Dog or Cat
  }
}

The Cat Class and Companion Class

package Animal

class Cat(a: Int) extends Animal {
  private var age: Int = a
  private var deaths: Int = 0

  def this() = this(0)

  override def speak: String = {
    if (this.isAlive) {
      "Meow"
    }
    else {
      "..."
    }
  }

  // I want to do this in the trait
  // override def isAlive: Boolean = this.deaths <= Cat.lives

  def setAge(age: Int): Unit = this.age = age

  def getAge: Int = this.age

  def getDeaths: Int = this.deaths

  def die(): Unit = this.deaths += 1

}

object Cat {
  val lives: Int = 9
}
2

2 Answers

2
votes

I'd include lives as an abstract method in Animal trait, similar to getDeaths (btw, Scala doesn't follow Java's naming conventions for getters and setters).

If you're familiar with Java, companion object in scala is similar to Java's static, meaning that type resolution of objects happens in compile time and it's not possible to use polymorphism the same way as you do with methods and fields of the class.

Here is the code:

trait Animal {
  def speak: String
  def getDeaths: Int
  def lives: Int

  def isAlive: Boolean = {
    getDeaths < lives
  }
}


class Cat(a: Int) extends Animal {
  override val lives: Int = 9

  private var age: Int = a
  private var deaths: Int = 0

  def this() = this(0)

   /* ... */
}

Alternatively, you can defined lives constant in companion object and reference it in concrete class when overriding lives method:

class Cat(a: Int) extends Animal {
  override val lives: Int = Cat.lives

  private var age: Int = a
  private var deaths: Int = 0

  def this() = this(0)

   /* ... */
}

object Cat {
  val lives = 9
}
2
votes

To access lives within a trait it either has to be a part of the trait, as @Alvean has pointed out, or you have to make it a requirement that classes extending the trait need to have it.

trait Animal { self: {val lives: Int} =>
  def isAlive: Boolean = getDeaths < lives
  . . .
}

class Cat(a: Int) extends Animal {
  val lives = Cat.lives  //required to be an Animal
  . . .
}