I have a case class called Cell and it has parameter-less methods for moving cells up, down, left, right...
case class Cell(topLeft: Coordinate, botRight: Coordinate) {
def up: Cell = {
Cell(
Coordinate(topLeft.x + 0, topLeft.y - 1)
, Coordinate(botRight.x + 0, botRight.y - 1))
}
}
It feels right that this up operation should be an instance method and be called like so:
val cell = Cell(x,y)
cell.up
However, if I make these operations static functions belonging to a companion object, like so,
object Cell{
def up(cell: Cell): Cell = {
Cell(
Coordinate(cell.topLeft.x + 0, cell.topLeft.y - 1)
, Coordinate(cell.botRight.x + 0, cell.botRight.y - 1))
}
...
}
then they seem more composable. Now I can pass around up, down, left,or right as a parameter of type Cell => Cell. As a parameter-less instance method it is equivalent to a value and so can't be passed as a function.
See both commented lines below.
private def move(move: Cell => Cell, team: Team, nucleus: Coordinate): Team = {
val (mover, others) = team.cells.partition(_.nucleus == Some(nucleus))
val newCell = move(mover.head) // Works using STATIC move
val newCell = mover.head.move // Doesn't Work (needs .up, .down etc...)
if(mover.nonEmpty){
if(isValidCellState(newCell)) {
Team(newCell :: others)
}else{
throw new BadMoveException("Invalid move from this position")
}
}else{
throw new BadMoveException("You didn't select a cell to move")
}
}
If I want both features:
It seems that I would need to define the methods statically in the companion object, but then define them in the class by referencing the static implementation
def up = Cell.up(this)
Is this bad practice, it seems a bit stinky.
Scala makes it really easy to create lambdas for cases like this:
move(_.up, team, nucleus)
You'll notice that this is even shorter than Cell.up
. For this reason, it seems unnecessary to also define them in the companion.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With