Optional.orElseChain ?
Remi Forax
forax at univ-mlv.fr
Mon Apr 20 14:27:37 UTC 2015
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 <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) :-)
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
>>
More information about the core-libs-dev
mailing list