Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is the use of exceptions a bad practice in scala?

Tags:

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

  • the use of exceptions is discouraged in scala (or functional programming in general)

  • there are any drawbacks in using them (regarding immutability or code concurrency)

  • exceptions are somehow in conflict with the principles or functional programming

  • you can think of a better way to code the given example

--

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...

like image 741
opensas Avatar asked Oct 22 '12 13:10

opensas


People also ask

Are exceptions bad practice?

Exceptions are not bad per se, but if you know they are going to happen a lot, they can be expensive in terms of performance. The rule of thumb is that exceptions should flag exceptional conditions, and that you should not use them for control of program flow.

When should exceptions not be used?

Don't use exceptions to signal something completely normal. Don't use exceptions to control your normal application flow. Use return values or state fields for flow control instead.

How do you handle exceptions in Scala?

try/catch/finally A basic way we can handle exceptions in Scala is the try/catch/finally construct, really similar to the Java one. In the following example, to make testing easier, we'll return a different negative error code for each exception caught: def tryCatch(a: Int, b: Int): Int = { try { return Calculator.

Should we always use exceptions?

As a general rule of thumb, throw an exception when your program can identify an external problem that prevents execution. If you receive data from the server and that data is invalid, throw an exception.


2 Answers

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 
like image 109
Travis Brown Avatar answered Sep 28 '22 08:09

Travis Brown


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...


  • You can check these links: Handling failures with Either -> Where is the stacktrace?

  • Kind of related to error handling too, which may interest you: Method parameters validation in Scala, with for comprehension and monads In which Travis Brown gave a more detailed answer, about using applicative functors and Scalaz to do fail-fast (first error blocks the process) or collection all errors of a suite of operations Same kind of question: Handling fail-fast failures when the return type is Option[Error]

  • And you can check this link which uses by-name parameters do perform of sequence of operations too. It may be a good alternative to using right projections in a for comprehension, but you can't create intermediare results :( Validation with a sequence of by-name parameters in Scala? I don't know if it can be used with your code exemple but I don't think so in this case (assuming your refreshApplicationToken is free of side effects and return a newly created immutable user instance, instead of mutating a token variable)

like image 42
Sebastien Lorber Avatar answered Sep 28 '22 08:09

Sebastien Lorber