Search code examples
scalaakka

Major differences between scala.util.Success and akka.actor.Status.Success?


I was wondering what is a comprehensive list of major differences between scala.util.Success and akka.actor.Status.Success?

And in what cases are they interchangable, if at all?


Solution

  • akka.actor.Status.Success is a wrapper which can be used as a message to quickly indicate to another actor that some operation completed successfully. Accordingly it provides no API beyond extraction.

    scala.util.Success[T] is one of the two subtypes of scala.util.Try, which is a monadic(-ish, it doesn't fully obey the monad laws, for a good reason) representation of an operation that can fail (in this case, Success contains the result of a successful operation). It's fairly rare, in practice, to directly create scala.util.Successs: you most often will create a Try.

    While they both encode some notion of "an operation was successfully attempted", scala.util.Success pertains more to the operation itself and akka.actor.Status.Success pertains more to the notification of success. In fact, it might well make sense, within the actor performing some operation which can fail, to have code like

    import akka.actor.Status
    import scala.util.{ Failure, Success, Try }
    
    def attemptAndReport(reportTo: ActorRef)(operation: => Unit): Unit =
      Try(operation) match {
        case _: Success =>
          // since it's a Unit-returning operation, there's only one value that could be wrapped by Success: ()
          reportTo ! Status.Success("operation succeeded")
        case Failure(e) =>
          reportTo ! Status.Failure(e)
      }
    

    That code is a little contorted to shoehorn both Successes. It would be more natural and useful to have something like

    import scala.util.control.NonFatal
    
     def attemptAndReport[Result](reportTo: ActorRef, successMsg: Result => Any)(operation: => Result): Unit = {
       val reportMsg = Try(operation)           // Try[Result]
         .map(r => Status.Success(successMsg))  // Try[Status.Success]... icky, but this is Akka Classic...
         .recover {
           case NonFatal(e) => Status.Failure(e)
         }                                      // Try[Status]
       reportMsg.foreach(reportTo ! _)
    }