0

I find the Success case is frequently buried in a match of many errors and one success. Is there another way to write this more cleanly such that sucess stands out perhaps by having all errors in a partial function? Or perhaps, there is another way to write it but just cleaner. I am in general just looking for other ideas/solutions that could be done.

results.responseCode match {
  case Success =>
    // TODO make this less smelly. can results.results be None?
    val searchResults = results.results.get.results
    SomeService.getUsersFromThriftResults(
      userRepo,
      searchResults,
      Seq(WithCounts)) map { userResults =>
      val renderableStatuses = getStatuses(searchResults, userResults.userMap)
      new JsonAction(transformedQuery, renderableStatuses)
    }
  case ErrorInvalidQuery =>
    throw new SomeBadRequestException("invalid query")
  case ErrorOverCapacity |
       ErrorTimeout =>
    throw new SomeServiceUnavailableException("service unavailable")
  //TODO: take care of these errors differently
  //          case ErrorInvalidWorkflow |
  //               ErrorBackendFailure |
  //               ErrorEventNotFound |
  //               PartialSuccess |
  case _ =>
    throw new SomeApplicationException("internal server error")
}
Dean Hiller
  • 19,235
  • 25
  • 129
  • 212

4 Answers4

3

You can chain partial functions with orElse.

Something like

type ResponseCode = Int // This would be the type of the results.responseCode.
type RespHandler = PartialFunction[ResponseCode, JsonAction]

val invalidQuery: RespHandler =
  { case ErrorInvalidQuery => ... }

val overCapacity: RespHandler =
  { case ErrorOverCapacity => ... }

results.responseCode match {
  case Success => ...
} orElse invalidQuery orElse overCapacity orElse ...

You can see more about this at this blog post: Chaining Partial Functions with orElse

Edit: This doesn't work as written, you'll need to compose the handling and then apply it (eg (success orElse invalidQuery ..)(results.getResponseCode)).

A better solution is to change it to return a Try[ResponseCode] and handle the exception in a Failure match block.

Daenyth
  • 35,856
  • 13
  • 85
  • 124
  • If you are able to change the API you should still use a `Try` or similar instead. – Daenyth Aug 20 '14 at 18:18
  • This is wrong. The case block for a match isn't a PF, though it looks like one. I guess no one typed this into REPL? It's true you can chain PFs as `(a orElse b)(x)`. – som-snytt Aug 20 '14 at 19:00
  • SO needs a feature where snippets have to run; or you could annotate that the snippet should be verified; maybe OP could request only verified snippets. – som-snytt Aug 20 '14 at 19:03
  • You're right, that doesn't work. I saw it for `catch` and figured you could do the same with match. – Daenyth Aug 20 '14 at 19:10
2

You could try Try[A].

Example from documentation:

import scala.util.{Try, Success, Failure}

def divide: Try[Int] = {
  val dividend = Try(Console.readLine("Enter an Int that you'd like to divide:\n").toInt)
  val divisor = Try(Console.readLine("Enter an Int that you'd like to divide by:\n").toInt)
  val problem = dividend.flatMap(x => divisor.map(y => x/y))
  problem match {
    case Success(v) =>
      println("Result of " + dividend.get + "/"+ divisor.get +" is: " + v)
      Success(v)
    case Failure(e) =>
      println("You must've divided by zero or entered something that's not an Int. Try again!")
      println("Info from the exception: " + e.getMessage)
      divide
  }
}
monnef
  • 3,903
  • 5
  • 30
  • 50
1

You should consider using Either[Throwable, A] to represent the result type.

http://tersesystems.com/2012/12/27/error-handling-in-scala/

Johnny Everson
  • 8,343
  • 7
  • 39
  • 75
1

You could convert result to Either[ResponseCode, Content]

def codeToEither(result: Result): Either[ResponseCode, Content] = 
  result.responseCode match {
    case Success => Right(result.results.get.results)
    case _       => Left(result.responseCode)
  }

And then fold over it

codeToEither(result).fold(
  errorCode => ... ,
  content   => ...
)

Or convert result to Either[Exception, Content] in the same way, if you like.

lambdas
  • 3,990
  • 2
  • 29
  • 54