David Moles
David Moles

Reputation: 51133

RxJava2 idiom for combining two Maybes

Given two Maybe values, how can I combine them into a single Maybe that will either:

  1. call onSuccess() whenever either of the source Maybes calls onSuccess
  2. call onComplete() whenever both of the source Maybes call onComplete()?

(Cf. Option.orElse() in Scala or Vavr.)

E.g., assuming the existence of a combine() method that does what I want:

combine(Maybe.just(a), Maybe.empty())  ≍ Maybe.just(a)
combine(Maybe.empty(), Maybe.just(b))  ≍ Maybe.just(b)
combine(Maybe.empty(), Maybe.empty())  ≍ Maybe.empty()
combine(Maybe.never(), /*anything*/ )  ≍ /*the thing*/ 
combine(/*anything*/,  Maybe.never())  ≍ /*the thing*/ 

At first I thought amb() & family were what I was looking for, but that completes as soon as either source Maybe completes, meaning if the first Maybe completes without a value, you never get the value from the second Maybe.

Right now I'm using

Maybe.mergeArray(m1, m2).firstElement()

which seems to do what I want, but I’m not certain it’s correct and I’m not certain it’s the cleanest way to do it. (For instance, if there’s some delay, will it call onSuccess() immediately when one or the other source does, or will it wait for both onComplete()s?)

Is this correct? Is there a more idiomatic approach?


ETA: I'm happy taking the first value; I don't need to wait for both to complete:

combine(Maybe.just(a), Maybe.just(b))  ≍ Maybe.just(/* a or b, don't care */)

(I can imagine situations in which I might prefer one or the other and want to indicate that by order of the arguments, but in that situation I suspect sequential would be better than parallel.)

Upvotes: 4

Views: 1497

Answers (1)

tynn
tynn

Reputation: 39853

There's a slightly different approach which might be a little nearer to your definition. This would be using Observable.switchMapMaybe():

Maps the upstream items into MaybeSources and switches (subscribes) to the newer ones while disposing the older ones (and ignoring their signals) and emits the latest success value of the current one if available while failing immediately if this Observable or any of the active inner MaybeSources fail.

Observable.just(m1, m2).switchMapMaybe(m -> m).firstElement()

But the approach using Maybe.mergeArray(m1, m2).firstElement() should be sufficient as well. The firstElement() operator emits the first element emitted by the mergeArray() flowable. This one is unordered and thus there's no information about the completion of any of the maybes.

Upvotes: 1

Related Questions