In my scala code (libraries as well as applications) I currently use a mixture of Option
and Try
, whenever either of both feels more apropriate.
I tend to implement "doSomething"-methods which can succeed with a return value or with a failure with Try
. That is, they can contain code which throw, or, when I detect errors "by hand", I artificially create a Throwable
and return a Failure
. The return value of those methods hence is a Try[ReturnType]
.
Now I read that creating exceptions is somewhat suboptimal, because it creates a stack trace (and hence is slow), which I don't even need. I also saw examples using a subclass of ControlThrowable
, which don't create a stack trace, however they also don't have a message, and Try
of course won't catch it.
Now my concrete question would be, should I generally favour Either
over Try
when I want to do runtime error-handling / method return values, and use Try
only in situations where I actually need to catch something (e.g. thirdparty code)?
That way I would not have to create clumsy Throwable
s, but instead only use e.g. strings in Left
for errors.
So basically:
Option
: every day usage for something which plain has a value or notTry
: catching exceptions within methods, but not used as return valueEither
: universal return value, containing error (string) or success valueWould this concept work out well, or is there a more viable/common approach?
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.
The Try type represents a computation that may either result in an exception, or return a successfully computed value. It's similar to, but semantically different from the scala. util. Either type. Instances of Try[T] , are either an instance of scala.
As Travis Brown has stated in the comments, there is no real convention and it is largely a cultural thing. Consistency is the most important thing here in order to keep your code readable. I've seen codebases which:
None
is a success and any Some(...)
contains the error message"Either[?, Throwable]
)Obviously these aren't good practices, but as long as you're consistent it doesn't really matter. The convention I personally use both recreationally and at work is:
Option
for when it's valid for a value to be missing (eg when parsing JSON using playframework).Try
when attempting to do something that might fail (unless it's in a Future, in which case I just use .recover
), where I care about matching the type of exception but also want the result of the Success where available.Either
when I don't want to return an Exception/Throwable in my "fail" case (though to be honest this is rare).Regardless of which of the above I use, I personally think it's best keep it wrapped up for as long as possible. This stops unnecessary Throwables being thrown (haha) around in your code, and makes debugging easier as there aren't any hidden getOrElse
lines returning default values (this can get very annoying in large codebases).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With