5

My new workplace is heavily using functional java Either for its error handling (http://www.functionaljava.org/javadoc/4.5/functionaljava/fj/data/Either.html).

exceptions are almost not used at all.

This is very annoying imo for many reasons. To name one: Every api call (which returns an Either) inside a method, must first check if the returned Either is an error or not before continuing to the next line. If it is an error, it is propogated back in the stack of method calls in an a form of an Either. Each method up in the stack will also need to check the retunred Either for the error, until finally we will get to the method that is responsible for handling the error. This results in a very badly structued java code. i cant really write a normal flow java code as i have to "stop" on every api call (so streams are out of the question). for example

Either<Error, Value> myMethod(String someVar) {
     Either<Error, Value> valEither someService.getSomething(someVar)
     if (valEither.isRight()) {
        Either<Error, Value> otherValue someService.getSomethingElse(valEither.right().value())
        if (otherValue.isRight()) ..... //you get the idea
     } else {
        //maybe log
        return valEither;
    }
}

I can, of course, use the monadic methods of Either (which i do) but that will not solve the core issues of having to "ask" the return type if its an error or a value. There are a lot more reasons why i think using Either as an infrastructure for error handling is not a good idea (long assigments statments, long methods, nested generics etc.).

To work around it, I thought of maybe throwing a specific exception for every api call which returns an "error" Either, and catch the exception once, on the top level method im currently working on.

Value val = myService.getSomething().rightOrThrow(new MyException("blaa"));

but that doesn't seem to be possible as the only method on the Either projection type which does something similiar, is throwing a java Error, which is not meant to be caught under (almost) any circumstances (I can accidently catch a stackoverflow or outofmemory errors).

myService.getSomething().right().valueE("some error msg");

Any suggestions or thoughts?

Thanks

yaarix
  • 490
  • 7
  • 18
  • What is your question, exactly? – Joe C Apr 24 '17 at 20:44
  • all I can say is [just flatmap that sh*t](http://stackoverflow.com/questions/8559537/where-does-the-flatmap-that-s-idiomatic-expression-in-scala-come-from) – Shlomi Apr 24 '17 at 23:37
  • My question is, did anyone else had to deal with what i have described and can share hes/hers approach. Btw there is no flatmap on the either type, only map, but even if there were its still a pain in the ass having to deal with an either on every second line – yaarix Apr 25 '17 at 05:57
  • Also, did any one figure out how to throw an exception if the given either is an error? – yaarix Apr 25 '17 at 06:01

2 Answers2

1

Back when I programmed in FJ I briefly had this problem too. I quickly realized that using Either this way was not very helpful, and that more native constructs like Exceptions were much lighter syntactically and certainly fit better with the language.

I did use Either when it made sense to compose further functionality using the functional methods (such as bimap and map et al), so something like:

 return someService.getSomething(someVar)
  .bimap((e)-> new Error("getSomething died for " + someVar, e), 
         (x)-> someService.getSomethingElse(x))
  .right().map((x)-> someService.getSAnotherThing(x));

Perhaps this construct seems to make much more sense with languages that supports pattern matching..

Edit

As for how to throw an error, well, take a look at valueE implementation, you could simply write your own static version that throws whatever you like

Shlomi
  • 4,708
  • 1
  • 23
  • 32
  • Hi and thanks for your reply. Indeed i can implement my own error function, just thought maybe there was a better idea by using some of the Either type functionality. I'm afraid it will be very hard to abandon the use of Either in the system i'm working on as it is a pretty large code base and Either is heavily used on all levels (part of the reasons using either like that is bad). Any suggestions of how to gradually move to exceptions is very welcome – yaarix Apr 26 '17 at 05:32
  • You dont have to move to exceptions, but start to structure code using Either in a similar way the the one I showed. As you experienced, stopping and asking for the content of Either is a terrible way to use it, but you dont have to. Instead you need to compose further functionality using `map`, `bimap` and the rest. Also, if you throw a runtime exception in the error case of `bimap`, does it not do what you want? – Shlomi Apr 26 '17 at 06:20
  • I can't really use bimap and throw and exception as you suggested (if i understood you correctly) as bimap expect a function which returns Some object. I can do something like: static Object fail(withMsg) {throw new SomeException(msg)) and call bimap with this method. i am using map and bimap but imo it is still a pain and not a normal java code – yaarix Apr 26 '17 at 13:04
0

The best solution i have found for throwing an exception in case the returned Either is an error one is:

either.right.on(err -> {throw new MyException(err);})

or use an helper method to make it a bit more readable:

 static <A> A willFailWith(String errorMsg) {
       throw new MyException(errorMsg);
 }
 either.right.on(err -> willFailWith(err))
yaarix
  • 490
  • 7
  • 18