Loose ends: Optional

Remi Forax forax at univ-mlv.fr
Fri Jun 7 11:25:20 PDT 2013


So let's be a little constructive.

I think we have clearly two options, and I'm fine with both of them:
Option A: We want to add map/flatMap.
   In that case, we also need to add a way to do the conversion back and 
fore to null (orNull() and fromNullable()).

   Note that the original code proposed by Brian below already does a 
null check in map().
   In that case, Optional is not only something that represent a value 
that doesn't exist,
   it's also a way see null as an object.

Option B: We don't want the conversion to null
   In that case, map should throw a NPE if the result of a call to the 
mapper function is null
   like it does when an Optional is created from a value.
   In that case, flatMap is in my opinion useless because the code that 
returns null will not magically
   be re-written to send an Optional as parameter.
   So Optional just represent when a value is absent or not and null is 
not a possible value.

Regardless the option chosen above,
   - Optional should not implement Iterable or have a forEach method. It 
makes the code weird to read.
   - filter doesn't seem to pull it's own weight, for what it worth, I 
never use it on an Option in Scala.

Rémi


On 05/24/2013 09:20 PM, Brian Goetz wrote:
> Proposed spec for methods on Optional, which would have the obvious 
> counterparts in Optional{Int,Long,Double}.
>
> These methods are known to be useful and seem mostly harmless now that 
> other things have settled.  (I don't think they greatly increase the 
> moral hazard of Optional in general, and they do make it more 
> expressive.)
>
>
>     /**
>      * If a value is present, and the value matches the given predicate,
>      * return an {@code Optional} describing the value, otherwise 
> return an
>      * empty {@code Optional}.
>      *
>      * @param predicate a predicate to apply to the value, if present
>      * @throws NullPointerException if the predicate is null
>      * @return an {@code Optional} describing the value of this {@code 
> Optional}
>      * if a value is present and the value matches the given predicate,
>      * otherwise an empty {@code Optional}
>      */
>     public Optional<T> filter(Predicate<T> predicate) {
>         Objects.requireNonNull(predicate);
>         if (!isPresent())
>             return this;
>         else
>             return predicate.test(value) ? this : empty();
>     }
>
>     /**
>      * If a value is present, apply the provided mapping function to it,
>      * and if the result is non-null, return an {@code Optional} 
> describing the
>      * result.  Otherwise return an empty {@code Optional}.
>      *
>      * @param <U> The type of the result of the mapping function
>      * @param mapper a mapping function to apply to the value, if present
>      * @throws NullPointerException if the mapping function is null
>      * @return an {@code Optional} describing the result of applying a 
> mapping
>      * function to the value of this {@code Optional}, if a value is 
> present,
>      * otherwise an empty {@code Optional}
>      */
>     public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
>         Objects.requireNonNull(mapper);
>         if (!isPresent())
>             return empty();
>         else {
>             U result = mapper.apply(value);
>             return result == null ? empty() : Optional.of(result);
>         }
>     }
>
>     /**
>      * If a value is present, apply the provided {@code Optional}-bearing
>      * mapping function to it, return that result, otherwise return an 
> empty
>      * {@code Optional}.
>      *
>      * @param <U> The type parameter to the {@code Optional} returned by
>      * @param mapper a mapping function to apply to the value, if present
>      *           the mapping function
>      * @throws NullPointerException if the mapping function is null or 
> returns
>      * a null result
>      * @return the result of applying an {@code Optional}-bearing mapping
>      * function to the value of this {@code Optional}, if a value is 
> present,
>      * otherwise an empty {@code Optional}
>      */
>     public<U> Optional<U> flatMap(Function<? super T, ? extends 
> Optional<U>> mapper) {
>         Objects.requireNonNull(mapper);
>         if (!isPresent())
>             return empty();
>         else {
>             return Objects.requireNonNull(mapper.apply(value));
>         }
>     }
>     }



More information about the lambda-libs-spec-observers mailing list