1

I'm using rx-scala, which is a subproject of rx-java. I'll be using Scala syntax and hope that everyone understands.

I'm encountering odd behavior, and I don't know whether it's a bug or misusage of rx operators on my behalf.

Problem Statement

I have an ox: Observable[X] and a trigger observable tr: Observable[()]. I want an observable oy that is a transformation of ox using function f: Function[X,Y], but only when triggered, since f is potentially expensive.

If there is no transformed value for the last value of ox, then oy should be null.

Some remarks:

  • ox is hot, as it is the result of UI events.
  • ox behaves correctly (both values and timing), as I checked with println debugging.
  • oy fires at the correct times; it's just using outdated values of ox, when its a not-null value.

Current Code

oy = ox.sample(tr).map(f).merge(ox.map(x => null))

The problem with the above code is: It works initally, but after some time, when triggering tr, oy is applying f to old values of ox. When not changing ox, if I trigger tr repeatedly, the results get newer and eventually catch up.

If I remove the merge to not reset to null, then everything works fine (probably, as the effect appears non-deterministic).

Question

My presented code is buggy.

  1. I'd like to know whether I'm doing something wrong.
  2. I welcome alternative ways of achieving what I need.

For the Jave people

  • generics/type annotation: ox: Observable[X] means Observable<X> ox
  • lambdas: x => null means x -> null
Community
  • 1
  • 1
ziggystar
  • 28,410
  • 9
  • 72
  • 124
  • Could you translate this into regular Java? – akarnokd May 22 '15 at 10:11
  • @akarnokd I added a section for the Java folks, though I doubt it's really necessary. I think in the code line you only have to replace `=>` with `->`. – ziggystar May 22 '15 at 10:22
  • Assuming merge() here is mergeWith() in RxJava, you are double-consuming ox if it is cold, for every of its values you emit null and potentially a transformed value if triggered, which can get out-of-sync. – akarnokd May 22 '15 at 10:28
  • @akarnokd I checked the source of rx-scala, and `merge` is using the static `Observable.merge` (with two args) from rx-java under the hood. Also, as I understand, `ox` is hot, as it is the result of GUI events (edits on the `X`). – ziggystar May 22 '15 at 10:32
  • There are a few buffers involved in the chain above: the serialization in sample() and the front-buffers of merge. What is tr exactly? The delaying effect may happen with map() if it runs async in respect of the emission of the trigger value. – akarnokd May 22 '15 at 10:53
  • @akarnokd `tr` comes from a `JButton` producing `void` values from the clicked events. So far, the problem only happened *with* the merge. But since the sampled values are wrong then, something has to go wrong at the sample step already. – ziggystar May 22 '15 at 11:36
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/78523/discussion-between-ziggystar-and-akarnokd). – ziggystar May 22 '15 at 12:02
  • Try `share`ing `ox` first: `val hotOx = ox.share; oy = hotOx.sample(tr).map(f).merge(hotOx.map(x => null))`, to rule out potentionally incorrectly implemented `ox`. Btw, in scala I'd use `Option` instead of `null`.. – Tomáš Dvořák May 27 '15 at 10:31

1 Answers1

0

I'm now using the following solution, which is short and apparently doesn't cause the problem to turn up:

tr.withLatestFrom(ox)((_,x) => f(x)) merge problem.map(_ => null)
ziggystar
  • 28,410
  • 9
  • 72
  • 124