Optional.orElseChain ?

Paul Sandoz paul.sandoz at oracle.com
Mon Apr 20 11:39:23 UTC 2015


Hi Remi,

I was gonna propose the same trick you mentioned in your last email :-) 

Similar tricks are possible for other cases like an equivalent of the recently added ifPresentOrElse, but that was considered a little obtuse.


On Apr 17, 2015, at 11:37 PM, Remi Forax <forax at univ-mlv.fr> wrote:
> Hi guys,
> I was trying to write a code that uses Optional and I think one method is missing.
> 

There is always one more (or four more including the primitive variants) :-)

We avoided supporting both the present and absent axes in the intermediate operations (e.g. additional methods with a supplier on absence).

This seems like a special intermediate operation, injecting an alternative optional on absence, rather than associated with the orElse terminal operations that return T:

  public Optional<T> or(Supplier<Optional<T>> mapper) {
      Objects.requireNonNull(mapper);
      if (isPresent()) {
          return this;
      } else {
          return Objects.requireNonNull(mapper.get());
      }
  }

But it has some terminal like qualities to it. It really only makes sense once, or once after each flatMap. I am concerned that a bunch of these sprinkled within a sequence of fluent calls might make it hard to reason about. 

As such a static method might be more appropriate, but then it's easy for someone to add one in their own code:

static <T> Optional<T> or(Optional<T> a, Supplier<? extends Optional<T>> b) {
    Objects.requireNonNull(a);
    Objects.requireNonNull(b);
    return a.isPresent() ? a : Objects.requireNonNull(b.get());
}

static <T> Optional<T> or(Optional<T> a, Optional<T> b) {
    Objects.requireNonNull(a);
    Objects.requireNonNull(b);
    return a.isPresent() ? a : b;
}

Perhaps the non-obvious thing about these is a null return should not be allowed.

I am somewhat on the fence here...

Paul. 


> Let suppose I want to load a type (like a class, an interface, etc) that can come
> either by reflection, or by using ASM.
> I will write an interface TypeProvider that is able to load a Type and
> i will chain the different type providers like this:
> 
>  TypeProvider asmTypeProvider = ...
>  TypeProvider reflectionTypeProvider = ...
>  TypeProvider provider =
>    asmTypeProvider.chain(reflectionTypeProvider).orFail();
> 
> so I've implemented TypeProvider like this:
> 
> public interface TypeProvider {
>  public Optional<Type> loadType(String name);
> 
>  public default TypeProvider chain(TypeProvider provider) {
>    return name -> {
>      Optional<Type> type = loadType(name);
>      return type.isPresent()? type: provider.loadType(name);
>    };
>  }
> 
>  public default TypeProvider orFail() {
>    return chain(fail());
>  }
> 
>  public static TypeProvider fail() {
>    return name -> Optional.empty();
>  }
> }
> 
> As you can see the code is not bad but the code of chain() could be simplified
> if there was a way on Optional to call a Supplier of Optional if an Optional is empty.
> Currently, orElse() takes a value, orElseGet takes a lambda that will return a value
> and there is no method that takes a lambda and return an Optional
> (like flatMap but but with a supplier that will be called if the Optional is empty).
> 
> If we add the method orElseChain(Supplier<? extends Optional<T>> supplier)
> perhaps with a better name ?, then the code of chain is better:
> 
>  public default TypeProvider chain(TypeProvider provider) {
>    return name -> loadType(name).orElseChain(() -> provider.loadType(name));
>  }
> 
> Am i the only one to think that this method is missing ?
> 
> regards,
> Rémi
> 




More information about the core-libs-dev mailing list