Forget Optional<T>, adopt Try<T>?
Zhong Yu
zhong.j.yu at gmail.com
Tue Jun 4 09:16:00 PDT 2013
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