opensas
opensas

Reputation: 63485

Is the use of exceptions a bad practice in scala?

I've seen many times pieces of scala code using Option (for simple values) or Either[List[Error], T] for handling errors.

this gives place to code like this

def createApplicationToken(accessToken: AccessToken): Either[List[Error], ApplicationToken] = {

// go to social info provider and fetch information
retrieveProviderInfo(accessToken).fold(
  errors  => Left(errors),
  info    => {
    // try to find user using the info from the provider
    // if it's not there, create user
    User.findOrCreateFromProviderInfo(info).fold(
      errors  => Left(errors),
      user    => {
        // try to create a fresh token and save it to the user
        user.refreshApplicationToken.fold(
          errors  => Left(errors),
          user    => Right(user.token)
        )
      }
    )
  }
)

Which produces a not so nice code nesting, forces you to deal with failures on every step, and also forces you to have all your functions return a Either[...]

So I'd like to know if

--

One could avoid the nesting by exiting the function as soon as an error is found using the return statement, but using return is also discouraged in scala...

Upvotes: 24

Views: 5107

Answers (3)

Travis Brown
Travis Brown

Reputation: 139038

The following version uses the fact that the right projection of Either is a monad, and is exactly equivalent to your code:

def createApplicationToken(accessToken: AccessToken) = for {
   info <- retrieveProviderInfo(accessToken).right
   user <- User.findOrCreateFromProviderInfo(info).right
   refr <- user.refreshApplicationToken.right
} yield refr.token

And does a much better job of showing off the advantages of Either.

More generally, the rules are the same as in Java: use exceptions for exceptional situations. You just might find that you change your definition of exceptional a bit when you're working in this style—e.g., invalid user input isn't really exceptional, a timed-out network request isn't really exceptional, etc.

Right-biased Either since Scala 2.12

You can now omit .right, so the following code is equivalent since Scala 2.12:

def createApplicationToken(accessToken: AccessToken) = for {
   info <- retrieveProviderInfo(accessToken)
   user <- User.findOrCreateFromProviderInfo(info)
   refr <- user.refreshApplicationToken
} yield refr.token

Upvotes: 25

Sebastien Lorber
Sebastien Lorber

Reputation: 92150

As om-nom-nom said, I asked a similar question: Throwing exceptions in Scala, what is the "official rule"

But it's not the only one I asked that may interest you, because I used to code with a lot of boilerplate code and a lot of indentation levels because of pattern matching etc...


Upvotes: 6

Keith Pinson
Keith Pinson

Reputation: 1725

The answer varies between what is ideal and what is practical. Ideally, avoid using exceptions. Practically, you can't live without them.

Scala seems to favor one-liners and along those lines v2.10 has the new monad Try:

import scala.util.Try

def percentCompleted( total:Int, done:Int ): Int = Try (done * 100 / total) getOrElse 100

percentCompleted( 0, 10 )    // Catches divide-by-zero and returns 100% instead

Upvotes: 2

Related Questions