Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What return type should a Scala method have if it can throw/return errors but has Unit return type?

Tags:

scala

So usually when we run a method that can both fail and return a value, we can encode our method return type as Either[SomeErrorType, ReturnType]. But many times we're running a method for its side effects, so the return type is Unit.

I could of course return an Either[SomeErrorType, Unit] but that definitely looks odd.

I could also just return an Option[SomeErrorType] but it doesn't really look a lot better (and breaks a possibly existing symmetry with other Either[SomeErrorType, NonUnitReturnType]s.

What's your approach in these cases?

  1. def m(): Unit // and implicitly know that exceptions can be thrown?;
  2. def m(): Either[SomeErrorType, Unit] // this is odd;
  3. def m(): Option[SomeErrorType] // this is odd, as it makes it look as the return type ofm()on a successful run is an error code.
  4. Other that I can't think of?

Thanks

like image 648
devoured elysium Avatar asked Dec 24 '16 11:12

devoured elysium


2 Answers

I use Try[Unit] for that case.

It encodes that the result of the method either succeeds or fails with some Exception, which can be further processed.

  • vs T => Unit Try lifts errors to the application level, encoding in the signature that some error can be expected and allowing the application to handle it as a value.
  • vs. Option[T] => Option is only able to encode that the operation had a value or not
  • vs. Either[SomeErrorType, Unit] => Try It's easier to work with using monadic constructions.

I've used something like this to implement checks. (imaginary example)

for {
    entity <- receiveEntity // Try[Entity]
    _ <- isRelational(entity)
    _ <- isComplete(entity)
    _ <- isStable(entity)
} yield entity

where each check is of the form: Entity => Try[Unit]

This will return the entity if all checks pass of the first error that failed the check.

like image 65
maasg Avatar answered Nov 13 '22 18:11

maasg


One more option that hasn't been mentioned yet is Validated from cats. All the options mentioned so far (Try, Either, Option) are monads, while Validated is an applicative functor. In practice this means you can accumulate errors from multiple methods returning Validated, and you can do several validations in parallel. This might not be relevant to you, and this is a bit orthogonal to the original question, but I still feel it's worth mentioning in this context.

As for the original question, using Unit return type for a side-effecting function is perfectly fine. The fact this function can also return error shouldn't get in your way when you define the "real" (right, successful, etc.) return type. Therefore, if I were to select from your original options, I'd go for Either[Error, Unit]. It definitely doesn't look odd to me, and if anyone sees any drawbacks in it, I'd like to know them.

like image 28
Haspemulator Avatar answered Nov 13 '22 19:11

Haspemulator