On 04/20/2015 01:39 PM, Paul Sandoz wrote:
Hi Remi,

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

yes, it's the same as
  optional.map(Stream::of).orElseGet(() -> Stream.empty())
(I use orElseGet() because Stream.empty() is not a constant !).


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 <[email protected]> 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) :-)

Yes, yet another one.

Note that technically, the only thing you need is to be able to do pattern matching on the two states, so if you have a way to do a flatMap() for the case with a value and a flatMap() for the case with no value,
you're done.

Doing a flatMap for the case with no value is exactly what you have called 'or'.
So it's yet another method to add but it's the last one :)


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());
       }
   }

yes,


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.

But mixing static methods and instance methods is not readable too,
instance methods goes left to right and static methods goes right to left.


I am somewhat on the fence here...

If you only knew the power of the Dark Side :)


Paul.

Rémi



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


Reply via email to