3

I have the following class model:

sealed abstract class Tile(val coordinate: Int, val isOccupied: Boolean) {
  def isEmpty() : Boolean
  def getPiece() : Option[Piece]
}

case class EmptyTile(coordinate: Int) extends Tile(coordinate, false) {
  override def toString: String = "" +coordinate
  override def isEmpty() = true
  override def getPiece() = None
}

case class OccupiedTile(coordinate: Int, val piece: Piece) extends Tile(coordinate, true) {
  override def toString = piece.toString
  override def isEmpty = false
  override def getPiece = Some(piece)
}

and I get the following error:

Error:(6, 22) overriding value coordinate in class Tile of type Int;
 value coordinate needs `override' modifier
case class EmptyTile(coordinate: Int) extends Tile(coordinate, false) {
                 ^

What am I doing wrong?

EDIT: Request to see Piece class, adding here:

import Alliance.Alliance
import PieceType.PieceType

abstract class Piece(val piecePosition: Int, val pieceType : PieceType, val alliance: Alliance) extends Movable {
}

object PieceType extends Enumeration {
  type PieceType = Value
  val PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING = Value
}
4
  • What is your version of Scala? Commented Jul 11, 2014 at 18:13
  • Could you share your Tile and Piece classes ? It would be helpful to REPL it out :) Commented Jul 11, 2014 at 18:13
  • Tile is included already, I'll add Piece Commented Jul 11, 2014 at 18:18
  • @vptheron I am using 2.10 I believe Commented Jul 11, 2014 at 18:19

2 Answers 2

5

Your abstract class Tile declares a val coordinate, making this value publicly accessible. Your case class EmptyTile implicitly declares coordinate as a val as well (case class "magic"). Basically, your case class is effectively trying to override a value already provided by your abstract class.

You can either remove the val in your abstract class declaration, or not make EmptyTile and OccupiedTile case classes.

Edit: proposed alternative after comment:

trait Tile {
  def coordinate: Int
  def isOccupied: Boolean
  def isEmpty() : Boolean = !isOccupied
  def getPiece() : Option[Piece]
}

case class EmptyTile(coordinate: Int) extends Tile {
  override def toString: String = "" +coordinate
  val isOccupied = false
  def getPiece() = None
}

case class OccupiedTile(coordinate: Int, val piece: Piece) extends Tile {
  override def toString = piece.toString
  val isOccupied = true
  def getPiece = Some(piece)
}
Sign up to request clarification or add additional context in comments.

4 Comments

If I remove the val in my abstract class - will it be a var? Or will it simply not exist in the base class? I suppose I can get rid of the case classing, but this really sucks...
@AmirAfghani No, it won't be a var, it just won't be used since the constructor isn't actually doing anything with it. If you want it accessible in Tile, I'd recommend removing it from the constructor and declaring def coordinate: Int (abstract) within it. Then you can keep your case classes.
By passing in coordinate as an Int, are you implicitly overriding the def declaration in the trait?
coordinate is undefined in the trait. Since it is a constructor argument of the case classes, you automatically implement it - not override, since the trait does not give any value to the member. The fact that it is an Int does not change anything.
1

case class automatically makes its arguments vals. This is why the argument coordinate to EmptyTile, understood as val coordinate, conflicts with the abstract class's val coordinate.

One way to fix this is to have coordinate and isOccupied be defined as abstract in Tile. Tile can even be a trait instead of an abstract class:

sealed trait Tile {
  def coordinate: Int
  def isOccupied: Boolean
  ...
}

case class EmptyTile(coordinate: Int) extends Tile {
  def isOccupied = false
  ...
}

case class OccupiedTile(coordinate: Int, piece: Piece) extends Tile {
  def isOccupied = true
  ...
}

5 Comments

thanks for your answer. Doesn't it seem wrong though to have Tile be a trait vs a 'noun' like thing? It seems like abstract classes with case class overrides are just not developer friendly in Scala. +1 for the answer
Another way to look at it is that in your case, the functionality you need from Tile could be completely specified as a trait (common interface), so why use a class when a trait would work just as well? See stackoverflow.com/q/1991042
In terms of "noun" vs. "trait", you can read EmptyTile extends Tile as "EmptyTile is a Tile, and a Tile is something that has these properties"... I'm not sure what's not-noun-like about that.
I suppose you're right. I was viewing traits as interfaces - which perhaps is wrong
I think it's correct to view them as interfaces, which is exactly why they work well for your Tile.

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.