What is the general way to implement a finite state machine (or finite state transducer) in Scala?
I often find myself in need for state machine implementation. My typical implementation looks like
object TypicalFSM { // actually — finite state transducer
type State
case object State1 extends State
case object State2 extends State
type Message
case object Message1 extends Message
type ResultMessage
case object ResultMessage1 extends ResultMessage
}
import TypicalFSM._
class TypicalFSM extends ((Message) =>Seq[ResultMessage]){
var state:State = State1
def apply(message:Message):Seq[ResultMessage] = (state, message) match {
case (State1, Message1) =>
state = State2
Seq(ResultMessage1, ResultMessage2)
}
}
What I dislike is the mutable var which makes the solution thread unsafe. Also the FSM topology is not clear.
How to create FSMs in a functional way?
It also would be very good to draw FSM-graph in .dot format
Akka FSM has a good property of allowing to associate some Data with a State, not only giving an object name. This is also appreciated.
(However, Akka FSM is not always convenient to use as it is asynchronous and sometimes a bit heavy-weight.)
This is probably not what you are looking for, but I think it's an interesting concept.
object TypicalFSM {
sealed trait State
final class State1 extends State
final class State2 extends State
sealed trait Message
case class Message1(s: String) extends Message
case class Message2(s: String) extends Message
sealed trait ResultMessage
object ResultMessage1 extends ResultMessage
object ResultMessage2 extends ResultMessage
}
import TypicalFSM._
case class Transformation[M <: Message, From <: State, To <: State](
f:M => Seq[ResultMessage]) {
def apply(m:M) = f(m)
}
object Transformation {
implicit def `message1 in state1` =
Transformation[Message1, State1, State2] { m =>
Seq(ResultMessage1, ResultMessage2)
}
implicit def `message1 in state2` =
Transformation[Message1, State2, State2] { m =>
Seq(ResultMessage1)
}
implicit def `message2 in state2` =
Transformation[Message2, State2, State1] { m =>
Seq(ResultMessage2)
}
}
class TypicalFSM[CurrentState <: State] {
def apply[M <: Message, NewState <: State](message: M)(
implicit transformWith: Transformation[M, CurrentState, NewState]) = {
this.asInstanceOf[TypicalFSM[NewState]] -> transformWith(message)
}
}
Usage would be like this:
def test() = {
val s1 = new TypicalFSM[State1]
// type of s1: TypicalFSM[State1]
val (s2, r1) = s1(Message1("m1"))
// type of s2: TypicalFSM[State2]
val (s3, r2) = s2(Message1("m1"))
// type of s2: TypicalFSM[State2]
val (s4, r3) = s2(Message2("m2"))
// type of s2: TypicalFSM[State1]
// val (s5, r4) = s4(Message2("m2"))
// Fails with:
// 'No transformation available for TypicalFSM.Message2 in TypicalFSM.State1'
// type of s5: TypicalFSM[State1]
}
Your use case would strongly determine the structure of the code in this concept. The use case really determines how much type information you want to keep.
I this concept because the state is kept using the type system and that illegal transitions are reported at compile-time.
Related
Say I have a Cake that can cycle through a number of states:
sealed trait State extends Product with Serializable
object State {
final case object Raw extends State
final case class JustRight(temperature: Int) extends State
final case class Burnt(charCoalContent: Double) extends State
}
final case class Cake[S <: State](name: String, state: S)
This is nice, because now I can make sure that I only try to put Raw cakes into the oven, instead of eating them right away.
But sometimes I just have a Cake[State] lying around and want to try to eat it, but only if it's in an edible state. I could of course always pattern match on cake.state, but I thought it should be possible to save myself a few keystrokes by adding a method def narrow[S <: State]: Cake[State] => Option[Cake[S]].
However, now I'm struggling to actually implement that function. The compiler accepts Try(cake.asInstanceOf[Cake[S]]).toOption, but it seems that would always succeed (I guess because the type parameter is erased, and actually any type A would be accepted here, not just S). What seems to work is Try(cake.copy(state = cake.state.asInstanceOf[S])).toOption, but now I've made a superfluous copy of my data. Is there another better way? Or is that whole encoding maybe flawed from the get-go?
You can solve this problem using a typeclass that checks and casts (in a typesafe way) the type of the state.
sealed trait State extends Product with Serializable
object State {
final case object Raw extends State
type Raw = Raw.type
final case class JustRight(temperature: Int) extends State
final case class Burnt(charCoalContent: Double) extends State
sealed trait Checker[S <: State] {
def check(state: State): Option[S]
}
object Checker {
private def instance[S <: State](pf: PartialFunction[State, S]): Checker[S] =
new Checker[S] {
val f = pf.lift
override def check(state: State): Option[S] = f(state)
}
implicit final val RawChecker: Checker[Raw] = instance {
case Raw => Raw
}
implicit final val JustRightChecker: Checker[JustRight] = instance {
case s # JustRight(_) => s
}
implicit final val BurntChecker: Checker[Burnt] = instance {
case s # Burnt(_) => s
}
}
}
final case class Cake[S <: State](name: String, state: S)
def narrow[S <: State](cake: Cake[State])(implicit checker: State.Checker[S]): Option[Cake[S]] =
checker.check(cake.state).map(s => cake.copy(state = s))
Which you can use like this:
val rawCake: Cake[State] = Cake(name = "Foo", state = State.Raw)
narrow[State.Raw](rawCake)
// res: Option[Cake[State.Raw]] = Some(Cake(Foo,Raw))
narrow[State.JustRight](rawCake)
// res: Option[Cake[State.JustRight] = None
BTW if you want to avoid the copy, you may change check to just return Boolean and use a dirty asInstanceOf.
// Technically speaking it is unsafe, but it seems to work just right.
def narrowUnsafe[S <: State](cake: Cake[State])(implicit checker: State.Checker[S]): Option[Cake[S]] =
if (checker.check(cake.state)) Some(cake.asInstanceOf[Cake[S]])
else None
(You can see the code running here)
If you don't know the specific type of your Cake's state at compile time, you might want to use ClassTag to check the type of your state instead, because throwing and catching ClassCastExceptions doesn't seem like a good idea to me:
def narrow[S <: State](cake: Cake[_])(implicit classTag: ClassTag[S]): Option[Cake[S]] =
Option.when(classTag.runtimeClass.isInstance(cake.state))(cake.asInstanceOf[Cake[S]])
Scastie
This works by checking if the cake's state is an instance of the erased class of S. If your states take type parameters, however, you may want to use TypeTag instead.
However, if you do know the specific type, you might want to use =:= <:< to check (<:< rejects Cake[State]):
def narrow[S <: State] = new NarrowFn[S]
class NarrowFn[S <: State] {
def apply[S2 <: State](cake: Cake[S2])(implicit ev: S2 <:< S = null): Option[Cake[S]] =
Option.when(ev != null)(cake.asInstanceOf[Cake[S]])
}
Scastie
Note that neither of these are great solutions, and I'd suggest just making a separate method for each case and use plain pattern matching to get your answer.
I'm using two Scala libraries that both rely on implicit parameters to supply codecs/marshallers for case classes (the libraries in question are msgpack4s and op-rabbit). A simplified example follows:
sealed abstract trait Event
case class SomeEvent(msg: String) extends Event
case class OtherEvent(code: String) extends Event
// Assume library1 needs Show and library2 needs Printer
trait Show[A] { def show(a: A): String }
trait Printer[A] { def printIt(a: A): Unit }
object ShowInstances {
implicit val showSomeEvent = new Show[SomeEvent] {
override def show(a: SomeEvent) =
s"SomeEvent: ${a.msg}"
}
implicit val showOtherEvent = new Show[OtherEvent] {
override def show(a: OtherEvent) =
s"OtherEvent: ${a.code}"
}
}
The Printer for the one library can be generic provided there's an implicit Show for the other library available:
object PrinterInstances {
implicit def somePrinter[A: Show]: Printer[A] = new Printer[A] {
override def printIt(a: A): Unit =
println(implicitly[Show[A]].show(a))
}
}
I want to provide an API that abstracts over the details of the underlying libraries - callers should only need to pass the case class, internally to the API implementation the relevant implicits should be summoned.
object EventHandler {
private def printEvent[A <: Event](a: A)(implicit printer: Printer[A]): Unit = {
print("Handling event: ")
printer.printIt(a)
}
def handle(a: Event): Unit = {
import ShowInstances._
import PrinterInstances._
// I'd like to do this:
//EventHandler.printEvent(a)
// but I have to do this
a match {
case s: SomeEvent => EventHandler.printEvent(s)
case o: OtherEvent => EventHandler.printEvent(o)
}
}
}
The comments in EventHandler.handle() method indicate my issue - is there a way to have the compiler select the right implicits for me?.
I suspect the answer is no because at compile time the compiler doesn't know which subclass of Event handle() will receive, but I wanted to see if there's another way. In my actual code, I control & can change the PrinterInstances code, but I can't change the signature of the printEvent method (that's provided by one of the libraries)
*EDIT: I think this is the same as Provide implicits for all subtypes of sealed type. The answer there is nearly 2 years old, I'm wondering if it's still the best approach?
You have to do the pattern matching somewhere. Do it in the Show instance:
implicit val showEvent = new Show[Event] {
def show(a: Event) = a match {
case SomeEvent(msg) => s"SomeEvent: $msg"
case OtherEvent(code) => s"OtherEvent: $code"
}
}
If you absolutely need individual instances for SomeEvent and OtherEvent, you can provide them in a different object so they can be imported separately.
If Show is defined to be contravariant (i.e. as trait Show[-A] { ... }, with a minus on the generic type) then everything works out of the box and a Show[Event] is usable as a Show[SomeEvent] (and as a Show[OtherEvent] for that matter).
If Show is unfortunately not written to be contravariant, then we might have to do a little bit more juggling on our end than we'd like. One thing we can do is declare all of our SomeEvent values as simply Events, vis a vis val fooEvent: Event = SomeEvent("foo"). Then fooEvent will be showable.
In a more extreme version of the above trick, we can actually hide our inheritance hierarchy:
sealed trait Event {
def fold[X]( withSomeEvent: String => X,
withOtherEvent: String => X ): X
}
object Event {
private case class SomeEvent(msg: String) extends Event {
def fold[X]( withSomeEvent: String => X,
withOtherEvent: String => X ): X = withSomeEvent(msg)
}
private case class OtherEvent(code: String) extends Event {
def fold[X]( withSomeEvent: String => X,
withOtherEvent: String => X ): X = withOtherEvent(code)
}
def someEvent(msg: String): Event = SomeEvent(msg)
def otherEvent(code: String): Event = OtherEvent(code)
}
Event.someEvent and Event.otherEvent allow us to construct values, and fold allows us to pattern match.
I am new to scala and thus my question might be due to a lack of understanding of abtract types and traits.
I currently have a Sensor trait which is generic and defines a value and newValue method.
trait Sensor[T] {
def value: T
def newValue(): Unit = {}
}
One concrete implementation of Sensor is MemorySensor, which just uses a variable to store the value and has a set value method which sets the value and fires the newValue method.
class MemorySensor[T] extends Sensor[T] {
var internalValue: T = null.asInstanceOf[T]
def setValue(newVal: T): Unit = {
internalValue = newVal
newValue()
}
def value: T = internalValue
}
There is also an AbstractSO (SO = subject + Observer) class which uses abstract types to implement Subject/Observer pairs.
class AbstractSO {
type O <: AbstractObserver
type S <: AbstractSubject
trait AbstractSubject {
this: S =>
def register(observer: O) = {
//we could use mutable collection here too
observers = observer :: observers
}
var observers: List[O] = List[O]()
def notifyObservers() = {
observers.foreach(o => o.notifyObserver(this))
}
}
trait AbstractObserver {
def notifyObserver(subject: S)
}
}
One example of a concrete Subject/Observer is the ActionSO
object ActionSO extends AbstractSO {
type S = ActionSubject
type O = ActionObserver
trait ActionSubject extends AbstractSubject {
def action() = {
notifyObservers()
}
}
trait ActionObserver extends AbstractObserver {
override def notifyObserver(actionSubject: ActionSubject) = {
println("action observer called")
}
}
}
Now I want to implement a concrete Subject/Observer-Pair for Sensors with the requirement that the SensorSubject should be a mixin trait for sensors.
So I guess the target would be to use the SensorSubject like this:
val x = new MemorySensor[Int] with SensorSubject[Int]
However whatever I try to implement the SensorSO, I always get either some kind of "illegal inheritance" error or "self-type does not conform to..".
As far as I know this cannot be done without creating an extra class that extends from AbstractSO, but uses generic types. (but I don´t know how this helps me to achieve my target anyways)
It would be very nice if someone could help me out!
EDIT:
As SergGr wanted to see my SensorSubject (which is what I don´t know how to implement, I will post one of my various tries)
Note however that this does NOT COMPILE
object SensorSO extends AbstractSensorSO {
//TODO: i shouldn´t use "Any" here - this won´t work
override type S = SensorSubject[Any]
trait SensorSubject[T] extends AbstractSensorSubject with Sensor[T] {
this: S => //this generates problems as well
}
}
Here is my AbstractSensorSO
class AbstractSensorSO extends AbstractSO {
type S <: AbstractSensorSubject
type O <: AbstractSensorObserver
trait AbstractSensorSubject extends AbstractSubject {
this: S =>
}
trait AbstractSensorObserver extends AbstractObserver {
}
}
As you can see the AbstractSensorSO basically doesn´t do anything, I just added it because it was mentioned in a hint to the solution that one needs an subclass of AbstractSO, before creating the concrete SensorSO object.
One problem I am facing is that the Sensor trait is generic so for the SensorSubject to use the Sensor trait AFAIK i have to make the SensorSubject generic too.
Normally this wouldn´t be a problem, but as i use abstract types I would have to define the "S" type in the SensorSO with generics too (e.g.
type S = SensorSubject[T]
But as the generic type "T" is not known in that context it obviously gives an error (as the generic "T" is only available the context of the generic trait SensorSubject)
If I try to drop the generic paramater when defining the type S, I also get an error message that the generic type parameter is missing.
And just writing
type S = SensorSubject[Any]
doesn´t solve the problem either
EDIT2:
To clarify what my target is:
SensorSubject should be an Mixin Trait, such that i can use normal Sensors(not only MemorySensors) and that if I want I can add "with SensorSubject[Int]" to the creation of the Sensor and then it functions as a SensorSubject
Which means i can register an observer and the observer is notified when i change the value of the Sensors(that now functions as SensorSubject)
Here is an example how I would like to use the SensorSubject[T] Trait:
//creating a sensor WITH the SensorSubject Trait
val sensorWithSubject= new MemorySensor[Int] with SensorSubject[Int]
sensorWithSubject.registerObserver(..)
//creating a normal Sensor WITHOUT SensorSubject
val normalMemSensor = new MemorySensor[Int]
You didn't provide any example of expected usage so my guess might be wrong. Still here is my attempt:
trait Sensor[T] {
def value: T
def newValue(): Unit = {}
}
class MemorySensor[T] extends Sensor[T] {
var internalValue: T = null.asInstanceOf[T]
def setValue(newVal: T): Unit = {
internalValue = newVal
newValue()
}
def value: T = internalValue
}
//////////////////////////////////
trait AbstractSubject[S <: AbstractSubject[S, O], O <: AbstractObserver[S, O]] {
this: S =>
def register(observer: O) = {
//we could use mutable collection here too
observers = observer :: observers
}
private var observers: List[O] = List[O]()
def notifyObservers() = {
observers.foreach(o => o.notifyObserver(this))
}
}
trait AbstractObserver[S <: AbstractSubject[S, O], O <: AbstractObserver[S, O]] {
def notifyObserver(subject: S)
}
//////////////////////////////////
trait SensorSubject[T, S <: SensorSubject[T, S, O], O <: SensorObserver[T, S, O]] extends Sensor[T] with AbstractSubject[S, O] {
this: S =>
}
trait SensorObserver[T, S <: SensorSubject[T, S, O], O <: SensorObserver[T, S, O]] extends AbstractObserver[S, O]
//////////////////////////////////
class MemorySensorSubject[T] extends MemorySensor[T] with AbstractSubject[MemorySensorSubject[T], MemorySensorObserver[T]] {
override def setValue(newVal: T): Unit = {
super.setValue(newVal)
notifyObservers()
}
}
trait MemorySensorObserver[T] extends AbstractObserver[MemorySensorSubject[T], MemorySensorObserver[T]]
and with that you can do
def test(): Unit = {
val sensor = new MemorySensorSubject[Int]
val observer = new MemorySensorObserver[Int] {
override def notifyObserver(subject: MemorySensorSubject[Int]): Unit = {
println(s"New value of $subject is ${subject.value}")
}
}
sensor.register(observer)
sensor.setValue(42)
}
and the output will be
New value of so.Main$MemorySensorSubject#363ee3a2 is 42
Probably the most important thing here is that MemorySensorSubject is an explicitly named type that thus can be used as S in F-bound generic constraint
I'm using Scala 2.10.4.
Please bare with the analogy - the actual code is deeply embedded in a complicated program, so rather than explain that, I’ll abstract the problem in a time honoured way to talk about Animals ;-)
In scala I have 2 traits - for example:
Animal, and HouseBase.
I have no access to change Animal, but I inherit from it with classes like Dog, Rabbit, Fish. Annoyingly I can’t change every subclass as I don’t own all the subclasses I use.
My animals all live somewhere - their homes must inherit from HouseBase. I can change HouseBase and it’s subclasses (via another layer of abstraction, if I must).
So a Dog is a subclass of Animal, and would live in a Kennel which is a subclass of HouseBase.
A Rabbit would live in a Hutch, and a Fish in a Tank.
Note there is not a 1:1 relationship enforced here - a Fish could also live in a Pond, and we’d have to be able to handle that too.
What I’d hoped was that -- given a concrete animal (eg Fish), that is referenced via an abstract type Animal, and given a concrete return type (eg Tank), Scala would be able to automagically pick the correct implicit parameter in the design I have below.
object AnimalSelectionProblem extends App {
def abstractFish : Animal = new Fish(true, 20.0)
def concreteFish : Fish = new Fish(false, 30.0)
def abstractDog : Animal = new Dog("tasty bone")
def concreteDog : Dog = new Dog("yummy bone")
def abstractRabbit : Animal = new Rabbit(5)
def concreteRabbit : Rabbit = new Rabbit(10)
import HouseImplicits._
val myTank1: Tank = HouseImplicits.create(abstractFish)
val myTank2: Tank = HouseImplicits.create(concreteFish)
val myKennel1: Kennel = HouseImplicits.create(abstractDog)
val myKennel2: Kennel = HouseImplicits.create(concreteDog) // This works
val myhutch1: Hutch = HouseImplicits.create(abstractRabbit)
val myhutch2: Hutch = HouseImplicits.create(concreteRabbit) // This works
}
However there are 2 related problems.
Problem 1 - If the animal is referenced as an abstract, then the implicit parameter will only look for functions that take the abstract type (Animal) rather than the underlying concrete type. I suspect the solution may be to use ClassTags, because Scala doesn’t seem to use runtime time information? I had a go at implementing this and got hopelessly l lost (I’m fairly new to Scala!).
Problem 2 - If my animal can live in more than one type of House then a similar issue occurs, that even if a concrete return type is specified, the compiler will find the 2 implicit objects for Fish ambiguous. I’m a bit stumped about what to do here!
I can dream up solutions with manual boilerplate to match the type at runtime, but this isn’t very extensible.
Any ideas gratefully received! Rest of the code is below.
Edit - these links seems to confirm what I had suspected. That compile time polymorphism is used and hence the runtime type cannot be known:
http://like-a-boss.net/2013/03/29/polymorphism-and-typeclasses-in-scala.html
https://softwareengineering.stackexchange.com/questions/258698/is-it-possible-to-have-ad-hoc-polymorphism-with-runtime-dispatch
So, I guess my question now is, given this, is there a way to modify my example to use runtime dispatch?
Animals:
trait Animal {
}
class Dog(val boneName: String) extends Animal
class Rabbit(val length: Int) extends Animal
class Fish(val likesFrogs: Boolean, val optimumTemp: Double) extends Animal
Houses and Implicits:
sealed trait HouseBase
// Made up some arbitrary member variables
case class Kennel(posessions: Seq[String]) extends HouseBase
case class Hutch(length: Int) extends HouseBase
case class Tank(waterTemp: Double) extends HouseBase
case class Pond(containsFrog: Boolean) extends HouseBase
sealed trait HouseCreator[A <: Animal, HB <: HouseBase] {
def create(animal: A): HB
}
object HouseImplicits {
implicit object BuildKennelForDog extends HouseCreator[Dog, Kennel] {
override def create(dog: Dog): Kennel = {
new Kennel(Seq(dog.boneName))
}
}
implicit object BuildTankForFish extends HouseCreator[Fish, Tank] {
override def create(fish: Fish): Tank = {
new Tank(fish.optimumTemp)
}
}
implicit object BuildPondForFish extends HouseCreator[Fish, Pond] {
override def create(fish: Fish): Pond = {
new Pond(fish.likesFrogs)
}
}
implicit object BuildHutchForRabbit extends HouseCreator[Rabbit, Hutch] {
override def create(rabbit: Rabbit): Hutch = {
new Hutch(rabbit.length*5)
}
}
def create[A <: Animal, H <: HouseBase](animal: A)(implicit house: HouseCreator[A,H]) : H = {
val newHouse = house.create(animal)
newHouse
}
}
So basically you want the following design:
At compile time the concrete type of HouseBase is known.
At compile time the concrete type of Animal is not known.
Create a specific type HouseBase for Animal provided runtime animal data.
Can't change Animal implementations, and don't really want to change HouseBase implementations.
The desirable thing is of course to have the concrete types of Animals available at compile time. Since there seems to be some knowledge of that (you know which HouseBase to create for an animal variable at compile time), you may try to use type-safe cast from shapeless to get an Option of a concrete Animal type.
But if it's not possible you have to use run-time dispatch of animals.
In that case I think the method create should have the following signature:
def create[HB <: HouseBase](animal: Animal): Option[HB]
You know the concrete type of the HouseBase so you may as well pass it as type parameter, and the return value is Option to account for a possible mismatch between the type of the provided animal and suitable animal types for a concrete HouseBase
One possible way to implement that is the following code with a single object that has all the knowledge about the production of HouseBases from Animals (it should be also possible to achieve the same thing by moving the creation code into companion objects of concrete HouseBases):
sealed trait HouseCreator[HB <: HouseBase] {
def create(animal: Animal): Option[HB]
}
object HouseCreator {
implicit object KennelCreator extends HouseCreator[Kennel] {
def create(animal: Animal): Option[Kennel] = animal match {
case dog: Dog => Some(Kennel(Seq(dog.boneName)))
case _ => None
}
}
implicit object HutchCreator extends HouseCreator[Hutch] {
def create(animal: Animal): Option[Hutch] = animal match {
case rabbit: Rabbit => Some(Hutch(rabbit.length * 5))
case _ => None
}
}
implicit object TankCreator extends HouseCreator[Tank] {
def create(animal: Animal): Option[Tank] = animal match {
case fish: Fish => Some(Tank(fish.optimumTemp))
case _ => None
}
}
implicit object PondCreator extends HouseCreator[Pond] {
def create(animal: Animal): Option[Pond] = animal match {
case fish: Fish => Some(Pond(fish.likesFrogs))
case _ => None
}
}
def create[HB <: HouseBase : HouseCreator](animal: Animal): Option[HB] =
implicitly[HouseCreator[HB]].create(animal)
}
Then you can call the functions this way:
val myTank1: Option[Tank] = HouseCreator.create[Tank](abstractFish)
val myTank2: Option[Tank] = HouseCreator.create[Tank](concreteFish)
// Types of the variables can also be inferred automatically
val myKennel1 = HouseCreator.create[Kennel](abstractDog)
val myKennel2 = HouseCreator.create[Kennel](concreteDog)
val myhutch1 = HouseCreator.create[Hutch](abstractRabbit)
val myhutch2 = HouseCreator.create[Hutch](concreteRabbit)
Also, the boilerplate code in HouseCreator can be reduced by using PartialFunctions:
sealed trait HouseCreator[HB <: HouseBase] {
def create: PartialFunction[Animal, HB]
}
object HouseCreator {
implicit object KennelCreator extends HouseCreator[Kennel] {
def create = {
case dog: Dog => Kennel(Seq(dog.boneName))
}
}
implicit object HutchCreator extends HouseCreator[Hutch] {
def create = {
case rabbit: Rabbit => Hutch(rabbit.length * 5)
}
}
implicit object TankCreator extends HouseCreator[Tank] {
def create = {
case fish: Fish => Tank(fish.optimumTemp)
}
}
implicit object PondCreator extends HouseCreator[Pond] {
def create = {
case fish: Fish => Pond(fish.likesFrogs)
}
}
def create[HB <: HouseBase : HouseCreator](animal: Animal): Option[HB] =
implicitly[HouseCreator[HB]].create.lift(animal)
}
What you want is for the compiler to deduce the run-time type of your subclass when it is declared statically as an instance of its superclass. This is provably impossible, so don't try to make it work unless you're hoping to win some kind of computer science award!
Instead of parameterizing your HouseCreator class, you could write it to have a single create() method that accepts an object of type Animal. It could create the appropriate House using a case match that matches based on the run-time subtype of Animal.
sealed trait HouseCreator {
def create(animal: Animal): HouseBase {
animal match {
case dog: Dog => new Kennel(Seq(dog.boneName))
case fish: Fish => // etc...
}
}
}
This would only be able to return a HouseBase object rather than a specific subclass (at least as I implemented it here). You could always case match the return value as well.
I'm using the Akka actors library here. The actors library defines a partial function "receive" which an actor that extends "actor" must implement to deal with various messages. I am creating a trait hierarchy for my application where trait "clockActor" extends Actor and "MasterClock" and "SubClock" extend "clockActor". I'm looking to add the common functionality of clocks in to the "clock" trait's receive function but then how to I add extra functionality to the receive function in the master and sub clock traits?
In short, I need a way to add extra case statements to a partial function.
Ideas?
As already suggested, you could easily compose PartialFunctions using orElse
trait ClockActor {
def commonOp = {
case ... => ...
}
}
class MasterClock extends Actor with ClockActor {
def receive = commonOp orElse masterOp
def masterOp = {
case ... => ...
}
}
class SubClock extends Actor with ClockActor {
def receive = commonOp orElse subOp
def subOp = {
case ... => ...
}
}
One thing that comes to mind is to do something like this:
trait ClockActor {
def pf:PartialFunction[String, Boolean] = {
case "a" => true
case v if(_pf.isDefinedAt(v)) => _pf.apply(v)
}
def _pf:PartialFunction[String, Boolean] = Map.empty
}
object MasterClock extends ClockActor {
override def _pf:PartialFunction[String, Boolean] = {
case "b" => false
}
println(pf("a"))
println(pf("b"))
}
which will output:
scala> MasterClock
true
false
The value true comes from the definition in the partial function of the Trait ClockActor, the falsecomes from the Object MasterClock.