Extending a partially implemented partial function in scala - scala

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.

Related

Summoning Scala implicits for subclasses of sealed abstract trait

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.

Define an object extending PartialFunction, implement directly with cases

I'm quite new to Scala but I already love it. I have read tutorials and articles on partial functions. What I would like to achieve is to have an object extending PartialFunction[...,...] and have it defined directly with cases, without needing to define isDefinedAt and apply methods.
For example
val partialfuncval : PartialFunction[Int,Boolean] = {
case 1 => false
}
is a valid definition of a partial function. But why can't I write
object PartialFunctionClass extends PartialFunction[Int,Boolean] {
case 1 => false
}
? This would cancel the need of defining isDefinedAt and apply and would make writing classes of certain (predefined by a lib I'm using) types easier.
Would one of these options suffice you?
Option 1
abstract class DelegatingPartialFunction[-T,+R](underlying: PartialFunction[T,R]) extends PartialFunction[T,R] {
def apply(t: T) = underlying.apply(t)
def isDefinedAt(t: T) = underlying.isDefinedAt(t)
}
Then:
object PartialFunctionClass extends DelegatingPartialFunction[Int,Boolean]({
case 1 => false
})
Option 2
trait DelegatingPartialFunction[-T,+R] extends PartialFunction[T,R] {
val underlying: PartialFunction[T,R]
def apply(t: T) = underlying.apply(t)
def isDefinedAt(t: T) = underlying.isDefinedAt(t)
}
Then:
object PartialFunctionClass extends DelegatingPartialFunction[Int,Boolean] {
val underlying = {
case 1 => true
}
}
Another option that might work depending on the use-case is
type PartialFunctionAlias = PartialFunction[Int,Boolean]
Then:
val partialfuncval: PartialFunctionAlias = {
case 1 => false
}

stacking multiple traits in akka Actors

I'm creating multiple traits which extend Actor. Then I want to create an actor class which uses some of these traits. However, I'm not sure how to combine the receive methods from all traits in the receive method of the Actor class.
Traits:
trait ServerLocatorTrait extends Actor {
def receive() = {
case "s" => println("I'm server ")
}
}
trait ServiceRegistrationTrait extends Actor {
def receive() = {
case "r" => println("I'm registration ")
}
}
The Actor:
class FinalActor extends Actor with ServiceRegistrationTrait with ServerLocatorTrait {
override def receive = {
super.receive orElse ??? <--- what to put here
}
}
Now if I send "r" and "s" to FinalActor it goes only in ServerLocatorTrait - which is the last trait added.
So the way this works right now is that it considers super the last trait added, so in this case ServerLocatorTrait
Question:
How do I combine the receive methods from all the traits in FinalActor?
PS - I've seen the actors with react example: http://www.kotancode.com/2011/07/19/traits-multiple-inheritance-and-actors-in-scala/
but it's not what I need
I'm not sure if you can combine the receive methods, since that would involve calling the super's super to obtain the ServiceRegistration's receive method. It would also be very confusing.
Another way would be to give different names to the receive method in the traits.
trait ServerLocatorTrait extends Actor {
def handleLocation: Receive = {
case "s" => println("I'm server ")
}
}
trait ServiceRegistrationTrait extends Actor {
def handleRegistration: Receive = {
case "r" => println("I'm registration ")
}
}
class FinalActor extends Actor with ServiceRegistrationTrait with ServerLocatorTrait {
def receive = handleLocation orElse handleRegistration
}
object Main extends App {
val sys = ActorSystem()
val actor = sys.actorOf(Props(new FinalActor))
actor ! "s"
actor ! "r"
sys.shutdown()
}
You can still use you initial approach, but you must chain the super.receive for each mixed trait.
trait IgnoreAll extends Actor {
def receive: Receive = Map()
}
trait ServerLocatorTrait extends Actor {
abstract override def receive = ({
case "s" => println("I'm server ")
}: Receive) orElse super.receive
}
trait ServiceRegistrationTrait extends Actor {
abstract override def receive = ({
case "r" => println("I'm registration ")
}: Receive) orElse super.receive
}
class FinalActor extends IgnoreAll with ServiceRegistrationTrait with ServerLocatorTrait
The latter solution looks pretty ugly to me.
Please see the below link for a more detailed discussion on the subject:
Extending Actors using PartialFunction chaining

Scala actor apparently not receiving messages

Could you please explain why the following code is not working as expected.
The actor is not printing the message
Thanks.
class Base {
def f() = { "This is Base" }
}
class Sub extends Base {
override def f() = { "This is Sub" }
}
case class myCase(x: Base)
import scala.actors._
object myActor extends Actor {
def act()
{
loop {
react {
case myCase(x) => x.f()
case msg => "unknown"
}
}
}
def main(args: Array[String]): Unit = {
this ! myCase(new Base)
this ! myCase(new Sub)
}
}
Answering the question
The problem has nothing whatsoever to do with inheritance or case classes (I have re-titled the question to reflect this). The code does not print anything for two reasons:
Because your code does not actually make any calls to println! Replace:
case myCase(x) => x.f()
with
case myCase(x) => println( x.f() )
Because you do not start your actor. I think your program would make more sense if the actor were an inner class:
object myActor extends App {
class MyActor extends Actor {
def act() {
loop {
react {
... // <-- You need to print stuff
}
}
}
}
val a = new MyActor
a.start() // <-- You need to start it
a ! myCase(new Base)
a ! myCase(new Sub)
}
Advice: case classes and inheritance
I would, however, offer the advice that using inheritance in the presence of case classes is a bad idea. I usually use the approach of declaring common behaviour/state in a trait:
sealed trait Base {
def f(): Unit
}
case class Sub() extends Base
Why is it a bad idea? Well, one of the contracts that case-classes give you is a rigid definition of equivalence (that is, an equals and hashCode implementation). In the presence of inheritance, this could well be misleading. That is, your code will probably not do what you expect. Consider the following;
scala> abstract class Base { val x: Int }
defined class Base
scala> case class Sub(s: String) extends Base { val x = util.Random.nextInt(100) }
defined class Sub
Now if I create 2 instances...
scala> Sub("Hey")
res2: Sub = Sub(Hey)
scala> Sub("Hey")
res3: Sub = Sub(Hey)
They are equivalent
scala> res2 == res3
res4: Boolean = true
But they do not have the same state
scala> res2.x
res5: Int = 28
scala> res3.x
res7: Int = 15
Note, I am not saying this is a bug. I'm just saying it's an area where you might find that you introduce a bug in your code because you have made the assumption that any state of the case class is included in its equivalence.

How can I add extra behaviour only to Lists of a certain type?

I have a small Scala/Neo4j application that links people and topics through "skilledAt" and "interestedIn" relations. It has a REST/Json Api (using Scalatra) and I ran into a typical type-erasure problem when I wanted to add an "asJson" method to List[Person] and List[Topic]. I would like to implement different Json serialization behaviour for the different content types but of course the types get erased. The best I've been able to come up with so far is the following runtime trick:
implicit def topicsOrPeopleAsJson[T](list: List[T]) = new {
def asJson: String = {
list match {
case head :: tail if (head.isInstanceOf[Topic]) => topicsToJson(list.asInstanceOf[List[Topic]])
case head :: tail if (head.isInstanceOf[Person]) => peopleToJson(list.asInstanceOf[List[Person]])
case _ => "[]"
}
}
private def peopleToJson(people: List[Person]) = {
...
}
private def topicsToJson(topics: List[Topic]) = {
...
}
}
This works just fine but I was wondering whether there was a better solution, maybe something including type classes, a topic I'm not very familiar with (yet).
Use another level of implicit (this is typeclasses indeed):
trait ListToJsonConverter[T] {
def asJson(l: List[T]) : String
}
implicit object PeopleToJsonConverter extends ListToJsonConverter[Person] {...}
implicit object TopicToJsonConverter extends ListToJsonConverter[Topic] {...}
implicit object DefaultJsonConverter extends ListToJsonConverter[Any] {
def asJson(l: List[Any]) = "[]"
}
implicit def topicsOrPeopleAsJson[T](list: List[T])(implicit ev : ListToJsonConverter[T]) = new {
def asJson = ev.asJson(list)
}
This may not be exactly what you asked for however. The converter will be chosen at compile time. So if you call with a list of person which the compiler knows only as a List[Any], it will not work as expected.
Why not do it the OO way?
trait JSONable {
def toJSON:String
}
class Person
class Topics
implicit def persontoJSONable(p:Person) = new PersonSerializer(p)
implicit def topicToJSONable(t:Topic) = new PersonSerializer(t)
class PersonSerializer(p:Person) extends JSONable {
override def toJSON = {
//...
}
}
class TopicSerializer(t:Topic) extends JSONable {
override def toJSON = {
//...
}
}
def ListAsJSON[T <% JSONable](l:List[T]) = {
l.map(_.toJSON)
}