Reputation: 16821
As part of my journey learning Scala and then Akka, I'm trying to understand how one can spot a PartialFunction
.
In the "Programming Reactive Systems" course, there is this example for an Actor:
class Toggle extends Actor {
def happy: Receive = {
case "How are you?" =>
sender ! "happy"
context become sad
}
def sad: Receive = {
case "How are you?" =>
sender ! "sad"
context become happy
}
def receive = happy
}
It's a pretty simple one and I would say I understand what it is trying to do. The thing that I don't understand is that happy
and sad
are of type Function1
(or at least that's my belief) and yet they can play the role of a PartialFunction
(receive
needs a PartialFunction).
And even worse than that, based on the Akka documentation, receive
is supposed to return a PartialFunction
(not being one):
abstract def receive: Actor.Receive
Scala API: This defines the initial actor behavior, it must return a partial function with the actor logic.
But as far as I can tell, happy
and sad
are not returning a PartialFunction
, they are one.
To wrap up my questions:
PartialFunction
against Function1
?receive
a PartialFunction
that returns Unit
? If the answer is yes, then why the documentation says the receive
should return a PartialFunction
?[UPDATE]
Based on the answer I've got from @Brian McCutchon, now I know that the receive
method is supposed to return a PartialFunction
. But that doesn't help with my confusion at all! Consider the following scenario:
def someFunction(): Receive = {
//Instantiates and returns a Receive object
}
class Toggle {
def happy: Receive = {
case "How are you?" =>
someFunction()
}
}
My question is, how does the Scala compiler know if the given code should be expanded to this:
class Toggle {
def happy: Receive = {
return {
case "How are you?" =>
someFunction() // <-- The returned object of this function call is dismissed
}
}
}
Or this:
class Toggle {
def happy: Receive = { // <-- Starting point of happy's body
case "How are you?" =>
someFunction() // <-- The Receive object is returned by this method
}
}
Or more importantly, how am I supposed to know which expansion will happen? And I thought modern programming languages are supposed to be more readable!!!
Upvotes: 3
Views: 134
Reputation: 8584
happy
andsad
are of type Function1
No, they are methods that return Receive
, which is a type alias for PartialFunction[Any, Unit]
. The type annotation you gave shows this return type. Partial functions can use the same lambda syntax as Function1
(and other SAM types), in which case they are distinguished only by context (in this case, your type annotation).
receive
is supposed to return aPartialFunction
(not being one)
You're confused on terminology. receive
is a method, not a PartialFunction
, as you declared it with def
. It returns a PartialFunction[Any, Unit]
(a.k.a Receive
). This should also clarify your confusion over happy
and sad
.
This is a reasonable source of confusion, as the syntax is so concise as to make it look like receive
and the PartialFunction
it returns are one thing. It might help to realize that your code could be expanded to this (though I wouldn't advise it in practice):
class Toggle extends Actor {
def happy: Receive = {
return {
case "How are you?" =>
sender ! "happy"
context become sad
}
}
def sad: Receive = {
return {
case "How are you?" =>
sender ! "sad"
context become happy
}
}
def receive = {
return happy
}
}
Per your update, the first expansion is correct. The second one doesn't make sense, as method bodies can't start with case
, which should clue you in that you're dealing with a lambda. To sum up: if a block starts with lambda arguments (e.g. x =>
), or it starts with case
and isn't a match
block, it's a lambda.
Upvotes: 6