Forget Optional<T>, adopt Try<T>?

Jed Wesley-Smith jed at wesleysmith.io
Tue Jun 4 15:31:34 PDT 2013


An Exception (or Throwable) on the left is really quite limiting. For
instance with the case where you want an obvious failure, and you don't
need to or want to produce a failure value, you'd simply want an
Either<Void, A> (or just Option<A> but I digress). For many other cases,
you want to provide richer data-types such as collections of errors if a
validation failed like Either<Iterable<ValidationFailure<String>>, A>.

The Throwable type is only to be part of the throw/throws machinery, there
is really no need to limit generally useful kit to it.

cheers,
jed.


On 5 June 2013 02:16, Zhong Yu <zhong.j.yu at gmail.com> wrote:

> On Tue, Jun 4, 2013 at 2:52 AM, Jed Wesley-Smith <jed at wesleysmith.io>
> wrote:
> > Actually Try is a (sort of*) monad on exception handling. It is really an
> > Either (or disjunction) class that is specialised to catch exceptions
> during
> > map/flatMap.
> >
> > As you point out, Option is isomorphic to an Either with no useful value
> on
> > the left hand side (Unit or Void for instance), and a true Either can
> return
> > something meaningful as to the reason why there was nothing.
> >
> > Making something that was returning @Nullable T an Optional<T> simply
> says
> > to the client, "there may not be a return value here". Making it return
> an
> > Either<X, T> says to the client "there may not be a return value here
> and X
> > is why". This is actually not necessary in many cases. Imagine a
> > Map.getOptional, there is no real reason to supply
> > BecauseThisMapDidntContainValue on the left hand side if the key isn't
> > found– it is somewhat obvious.
>
> Even though the failure is obvious, what's the harm of returning it
> anyway? It'll require extra work for API authors, but it doesn't
> affect API users at all. The failure object might become useful later
> where we need to take different actions based on different types of
> failures occurred earlier. Returning a vacuous state to imply the
> failure only works in the immediate vicinity of the callsite.
>
> (By failure I don't mean "error". Failure should be a checked
> exception, it is a "normal" result of the action)
>
> Though we can have both Option and Try, I don't see the reason to keep
> Option while Try covers all use cases of Option.
>
> And finally I propose to rename "Try" to "Result". A Result<T> is
> either a success with a value of type T, or a failure with an
> Exception.
>
> Zhong Yu
>
> >
> > So, while Either and Option to serve similar purposes, there are
> important
> > differences. Rather than choose one, you really want to have both in the
> > kit.
> >
> > cheers,
> > jed.
> >
> > * it is sort of a monad as a monad should really obey the contravariant
> > functor laws, and it doesn't due to the fact that composition is
> violated:
> > https://issues.scala-lang.org/browse/SI-6284
> >
> >
> > On 4 June 2013 14:21, Zhong Yu <zhong.j.yu at gmail.com> wrote:
> >>
> >> I'm thinking that if we have something like scala's Try<T>, it'll
> >> express APIs' intentions better than Optional<T>.
> >>
> >> Some people view Optional as a collection of either 0 or 1 element.
> >> That doesn't seem to be what an API author wants to express by
> >> returning an Optional. The actual intention is that, either the action
> >> succeeds with a value (not a collection of!), or it fails (with an
> >> unspecified or implied reason). Try<T> describes that intention
> >> precisely (but it probably needs a better name)
> >>
> >> Suppose we have a good old method that returns a nullable
> >>
> >>     /** return null if there's no element */
> >>     T getFirst();
> >>
> >> Why do we hate it? Probably because we need to insert null handling in
> >> the code path
> >>
> >>     T first = getFirst();
> >>     if(first==null)
> >>         blah blah
> >>     first.doSomething()...
> >>
> >> we would rather defer null handling to some later time, leaving the
> >> main code path cleaner. Java already has a way to do that - exception
> >> propagation. For example the method can be designed to throw
> >>
> >>     T getFirst() throw NotFoundExcpetion;
> >>     // for efficiency, throw a cached immutable exception object
> >>
> >>     T first = getFirst();  // may throw - exception will be handled
> >> somewhere else
> >>     // no null handling here
> >>     first.doSomething()
> >>
> >> But lots of try-catch blocks may make code look ugly. Try<T> may be
> nicer
> >>
> >>     /** fail with NotFoundException if  there's no element */
> >>     Try<T> getFirst();
> >>
> >>     Try<T> first = getFirst();
> >>     first.map().filter().recover()....
> >>
> >> So we don't need Optional. Try<T> does the same thing, and expresses
> >> the intention better. And Try<T> has broader use cases. It'll also
> >> appease those who prefer returning errors over throwing errors.
> >>
> >> Sounds good?
> >>
> >> Zhong Yu
> >>
> >
>


More information about the lambda-dev mailing list