I have an inner case class, specifically an event from this question, and want to match it, including the outer object:
class Player {
var _life = 20
def life = _life
def gainLife(life: Int) = execute(GainLife(life))
case class GainLife(life: Int) extends Event {
def execute() = _life += life
}
}
I can easily write an effect (a partial function) that replaces life events for a specific player:
//gain twice as much life
def effect(player: Player): ReplacementEffect = {
case player.GainLife(x) => player.GainLife(x * 2)
}
however, I can't do the same for other players. The closest I have come is this:
//only you gain life
def effect2(player: Player): ReplacementEffect = {
case evt: Player#GainLife => player.GainLife(evt.life)
}
But 1) this replaces even your own lifegain with a new lifegain, 2) I can't reference the player that originally gained life in the function and 3) I'm missing out on directly matching life
this way.
This could be expressed using a path-independent type like
case Player.GainLife(_player, life) if _player != player => GainLife(player, life)
Ideally, I want something like
case _player.GainLife(life) if _player != player => player.GainLife(life)
Is this possible somehow, or can I work around this? Or do I have to resort to making GainLife nested?
The closest I have come is to define my own unapply
method:
class Player {
self =>
var _life = 20
def life = _life
def gainLife(life: Int) = execute(GainLife(life))
case class GainLife(life: Int) extends Event {
def player = self
def execute() = _life += life
}
}
object Player {
object _GainLife {
def unapply(event: Player#GainLife) =
Some((event.player, event.life))
}
}
Note that naming the Player._GainLife
object Player.GainLife
instead would cause a name conflict, that is the most important downside here. Therefore, I chose to make that type available from outside the Player
namespace:
val GainLife = Player._GainLife
This allows to match using both player.GainLife.unapply and Player._GainLife.unapply in a concise way:
//gain twice as much life
def effect1(player: Player): ReplacementEffect = {
case player.GainLife(life) => player.GainLife(life * 2)
}
//only you gain life
def effect2(player: Player): ReplacementEffect = {
case GainLife(_player, life) if _player != player => player.GainLife(life)
}
//all players gain twice as much life
def effect3: ReplacementEffect = {
case GainLife(player, life) => player.GainLife(life * 2)
}
The last two examples look a little asymmetric, but that can be fixed with an apply
method if desired.