Sometimes there is so magic happens that I break my head figuring out on what the compiler does. For example in akka, receive is defined as:
def receive: Receive
type Receive = Actor.Receive
and Receive is defined as:
type Receive = PartialFunction[Any, Unit]
then we declare receive as:
def receive = {
case "a" => //do something
case "b" => //do something
case _ => //default
}
I am aware of PartialFunction but what I dont get is that how does it apply the message to receive. Aren't we suppose to provide apply and isDefinedAt because receive returns a PartialFunction?
Syntactically how does it apply receive to the message? DOes it do something like message match receive or something?
The compiler will automatically generate the isDefinedAt from the body and apply is the body itself. Where a partial function is expected, you can just write a block that consist of case expressions and the compiler will turn it into a partial function.
scala> val f: PartialFunction[Any, Any] = {
| case x: String => 3
| }
f: PartialFunction[Any,Any] = <function1>
scala> f.isDefinedAt("foo")
res1: Boolean = true
scala> f.isDefinedAt(23)
res2: Boolean = false
edit:
In the underlying akka code, receive will be called to set the handler function once and then for every arriving message it tries to apply the receive method and otherwise calls unhandled (see links).
So the handler will only be called, if it can handle the message, otherwise the message will be put in the deadletters mailbox.
edit2:
These are the relevant sections in the akka code:
Call handler if defined, otherwise call unhandled:
https://github.com/akka/akka/blob/master/akka-actor/src/main/scala/akka/actor/ActorCell.scala#L496
unhandled:
https://github.com/akka/akka/blob/master/akka-actor/src/main/scala/akka/actor/Actor.scala#L545
Related
Suppose I have many akka services which all return a case class of type AbcDto wrapped in a Try.
So I call all these services using map and get back a List[Future[Any]].
Now I use Future.sequence to convert this to Future[List[Any]].
How do I unwrap my final list of results? I want to process them only when all of them are a Success and even if one fails I want to throw an error.
I tried mapping Future[List[Any]] as:
val a: List[Future[Any]]
a.map {
case r: List[Success[AbcDto]] => println("hello")
}
But this gives error:
case r: List[Try[AbcDto]]. At this point its giving error: non-variable type argument scala.util.Try[AbcDto] in type pattern List[scala.util.Try[AbcDto]] (the underlying of List[scala.util.Try[AbcDto]])
since all akka services return AbcDtowrapped in a Try the proper type of val a should be List[Future[Try[AbcDto]]]. Now the desired result can be achieved by a combination of Future.sequence and flatMap operation to check for any Failures in the service as shown below.
val a: List[Future[Try[AbcDto]]] = ...
val result: Future[List[AbcDto]] = Future.sequence(a) flatMap {
case r: List[Try[AbcDto]] #unchecked if r.find(!_.isSuccess).isDefined => Future.failed(new RuntimeException("not all results are successful"))
case r => Future.successful(r.collect({ case Success(x) => x}))
}
Future[A] and Try[A] in the actor context are so similar that I see no point to return Try[A] from those actors. You just return A in case of success, which will be Future[A] on asking side, a List of which you can sequence and get Future[List[A]], which, in case of a single failure, will contain the first encountered exception. It seems to be exactly what you're asking for.
To communicate failure from an actor to the asker, you should send akka.actor.Status.Failure with the relevant instance of Throwable.
P.S. regarding comment that using try-catch is non-idiomatic Scala. It actually is. Here's how Try creation is implemented:
object Try {
/** Constructs a `Try` using the by-name parameter. This
* method will ensure any non-fatal exception is caught and a
* `Failure` object is returned.
*/
def apply[T](r: => T): Try[T] =
try Success(r) catch {
case NonFatal(e) => Failure(e)
}
}
As you can see, it uses try-catch inside. If Scala standard library authors are fine with that, so should be you. :)
If I understand you correctly (the types in your question are a bit confusing),
You start with a val responseFutures: List[Future[Any]] and after conversion you have a val responsesFuture: Future[List[Any]]. rogue-ones answer is correct, but it could use some clarification:
Your compiler error is caused by the fact that Success is not a class, but an extractor object with unapply for Try. Therefore you cannot use in in type extraction this way.
So something like case r: List[Try[AbcDto]] if r.forall(_.isSuccess) => println("hello") should compile. However, as AbcDto is erased, you will get a compiler warning about erasure. Thus the #unchecked.
UPDATE
Type erasure means, the compiler cannot check type argument type in pattern matches at compile time. In your case, all the compile knows of your input type is Future[List[Try[Any]]].
So
future.map {
case _: List[Try[AbcDto]] => ???
}
will cause a compiler warning because the compiler only sees.
future.map {
case _: List[Try[_]] => ???
}
The #unchecked annotation just suppresses the corresponding compiler warning.
In the end with the pattern match above you just cast whatever is coming in to Try[AbcDto] without any compile time type safety.
Any of you have an idea as to why the following compiles:
def foo() =
someObjectOfTypeFutureAny.asInstanceOf[Future[List[Bar]]]
foo()
Whilst the following does not:
def foo[T]() =
someObjectOfTypeFutureAny.asInstanceOf[Future[List[T]]]
foo[Bar]()
It comes down with the error 'List[T] is invalid type for the resulting GraphQL type Seq[Bar].
someObjectOfTypeFutureAny is what I receive from an Akka actor ask (which returns a List[Bar])
I'm using Sangria-Graphql
I built a basic application casting a list to another list using a generic, passing the function the generic like in the example above, which worked. So I'm not really sure where my error here is coming from.
My actual code:
def complexFieldResolver[Val, T](arguments: (Context[Unit, Val]) => List[String]): Field[Unit, Val] = {
Field("solution",
ListType(solutionEntityType),
arguments = OptionalEntityIdArgument :: OptionalEntityIdsArgument :: Nil,
resolve = ctx =>
viewActor.ask(Query(NodeType.Solution, arguments(ctx))).asInstanceOf[Future[List[T]]]
)
}
Gets called like this: complexFieldResolver[ApplicationEntity, SolutionEntity]((context) => getArguments(context, "solutionentity", context.value.solution))
The code being called:
case NodeType.Solution =>
graph.Vertex.findSolutionEntitiesByIds(ids).asInstanceOf[List[SolutionEntity]]
def findSolutionEntitiesByIds(entityIds: List[String]): List[models.SolutionEntity] =
Is there the concept of a Future that cannot fail in Scala?
I'm transforming a Future[Result], which may fail—therefore I handle both a Failure and a Success—into a Future[Option[String]], carrying an optional error message derived from the failure or success states. So far, so good.
Thing is now, I would like to formally (i.e., with the help of the type system) remember that this future will always hold a Success and that I won't need to handle the failure case in the future.
Is there a smart way to do this?
You cannot do that "with the help of type system" because there is no way for the type system to guarantee a Future will not fail, even if you promise that it won't.
Consider this:
Future { doStuff(); }
.recover { case _ => "Failed!" } // Now it always succeeds
.map { _ => Seq.empty[String].head } // Now it does not.
Even if you were going to make any further transformations impossible, once the Future has been declared to always succeed, that still does not help, because the exception handler (or whatever you do to convert the original future to the "always succeeding one") could throw.
Update: as pointed out in a comment below, the code snippet above is incorrect: the result of .map is not the same Future as the result of .recover. The point stands however. Here is the correct illustration:
Future { doStuff }
.recover { case _ => Seq.empty[String].head }
Isn't this what type-tagging is for?
scala> type Tagged[U] = { type Tag = U }
defined type alias Tagged
scala> type ##[T, U] = T with Tagged[U]
defined type alias $at$at
scala> trait OK ; trait Uncertain
defined trait OK
defined trait Uncertain
scala> type Sure[A] = Future[A] ## OK
defined type alias Sure
scala> type Unsure[A] = Future[A] ## Uncertain
defined type alias Unsure
scala> val f = Future.successful(42).asInstanceOf[Sure[Int]]
f: Sure[Int] = Future(Success(42))
then
scala> object X { def p(f: Sure[_]) = "sure" ; def p(f: Unsure[_])(implicit d: DummyImplicit) = "unsure" }
defined object X
scala> X.p(f)
res1: String = sure
It doesn't remain sure under map, of course.
I've found some weird behaviour in Akka. When I matching the pattern, I cannot add a message to the list:
var msgs: List[Message] = Message() :: Nil
...
override def receive: Receive = {
case msg # Message => {
msgs = msgs.::(Message()) // ok
//msgs = msgs.::(msg) // doesn't work
sender ! "Thanks!"
}
case Request => { sender ! msgs.head }
case _ =>
}
Is this a bug in Scala or Akka?
To fix it I need to case the type
msgs = msgs.::(msg.asInstanceOf[Message])
which is not a convenient solution.
The problem is that you are making a subtle mistake in the matching happening in your case statement. You are matching there against the Message companion object, not the Message case class.
Another way of looking at it is that the case x # Y syntax can be thought of as saying "match with any instance of type Y, and then run the equivalent of val x: Y = <incoming value>.asInstanceOf[Y]", but here the inferred type you are providing is a parameter-less type called Message, which the compiler takes to be object Message, not case class Message().
So, to fix the line, write in the parameter list. For example, if the Message class is defined as:
case class Message()
this will be:
case msg # Message() => ...
If instead we had, say:
case class Message(text: String, id: Int)
then the case statement becomes something like:
case msg # Message(txt, is) => ...
or, if we don't care (or need to use) the text and id parameters:
case msg # Message(_, _) => ...
For a slightly more technically correct description of what is happening here, the case statement is actually attempting a match with any "unapply" methods available in the companion object (also called "extractors"). By default, there will be both an apply and an unapply method provided for free in the companion object for any case class that match exactly the parameter list provided in the case class constructor. In the second version of the Message class above, the relevant unapply method will have a signature like:
def unapply(text: String, id: Int): Option[Message]
You can read more about extractors here and here.
I am new to Scala programming and having some trouble understanding how actors works and how to use them correctly.
Looking at the source code of an Akka actor, the following is exposed:
trait Actor {
def receive: Actor.Receive // Actor.Receive = PartialFunction[Any, Unit]
}
My first impression of this is that Actor is a trait that exposes one abstract method, receive which takes no arguments and then returns a partial function. First question, is this the correct interpretation of the API?
Next, I looked at the documentation for how to implement actors. The examples look something like this:
class HelloActor extends Actor {
def receive = {
case "hello" => println("hello back at you")
case _ => println("huh?")
}
}
Clearly there is some pattern matching going on here, but I'm having trouble understanding how this works. For instance, let's say I wanted to invoke the receive method directly without using something like send, how would I do it?
as others already answered, you never should directly call methods on Actors. But your question seems to be more about "how does PartialFunction work in Scala?", right?
In Scala the PartialFunction[In, Out] has a bit of compiler generated code for methods like isDefinedAt, so you can ask a partial function if it's defined for a certain argument:
scala> val fun: PartialFunction[Any, String] = {
| case 42 => "yes"
| }
fun: PartialFunction[Any,String] = <function1>
scala> fun.isDefinedAt(12)
res0: Boolean = false
scala> fun.isDefinedAt(42)
res1: Boolean = true
scala> fun(42)
res2: String = yes
scala> fun(12)
scala.MatchError: 12 (of class java.lang.Integer)
```
We use the isDefinedAt method before we apply a message to a receive function, and if it's not able to handle the message we pass it into unhandled(msg), which usually just logs the message to dead letters so you can figure out that your Actor didn't handle a message.
For instance, let's say I wanted to invoke the receive method directly without using something like send, how would I do it?
You would not.
Directly invoking the receive function of an actor without going through its ActorRef breaks the guarantees of the actor model:
Actors process exactly one message at a time.
An actor's internal state can only be mutated from the receive function.
(among others, see What is an actor?)
When you send an ActorRef a message, you aren't directly talking to the actor. Hidden behind the ActorRef are any number of implementation details—you could be sending a message to a router or a remote actor or a dead actor (or all three!). Isolating an actor's details behind this reference allows the guarantees that are the entire point of the actor model.