16

What is the definition of a "glitch" in the context of Functional Reactive Programming?

I know that in some FRP frameworks "glitches" can occur while in others not. For example RX is not glitch free while ReactFX is glitch free [1].

Could someone give a very simple example demonstrating how and when glitches can occur when using RX and show on the same example how and why the corresponding ReactFX solution is glitch free.

Thanks for reading.

Community
  • 1
  • 1
jhegedus
  • 20,244
  • 16
  • 99
  • 167

3 Answers3

21

Definition

My (own) favorite definition:

A glitch is a temporary inconsistency in the observable state.

Definition from Scala.Rx:

In the context of FRP, a glitch is a temporary inconsistency in the dataflow graph. Due to the fact that updates do not happen instantaneously, but instead take time to compute, the values within an FRP system may be transiently out of sync during the update process. Furthermore, depending on the nature of the FRP system, it is possible to have nodes be updated more than once in a propagation.

Example

Consider integer variables a, b. Define sum and prod such that
sum := a + b,
prod := a * b.

Let's rewrite this example to JavaFX:

IntegerProperty a = new SimpleIntegerProperty();
IntegerProperty b = new SimpleIntegerProperty();
NumberBinding sum = a.add(b);
NumberBinding prod = a.multiply(b);

Now let's write a little consistency check:

InvalidationListener consistencyCheck = obs -> {
    assert sum.intValue() == a.get() + b.get();
    assert prod.intValue() == a.get() * b.get();
};

sum.addListener(consistencyCheck);
prod.addListener(consistencyCheck);

a.set(1);
b.set(2);

This code fails with an assertion error on the last line, because:

  • b is updated (to 2)
    • sum is updated (to 3)
      • `consistencyCheck` is triggered, `a == 1`, `b == 2`, but `prod == 0`, because `prod` has not been updated yet

This is a glitch — prod is temporarily inconsistent with a and b.

Glitch Elimination Using ReactFX

First note that ReactFX is not "glitch free" out of the box, but it gives you tools to eliminate glitches. Unless you take some conscious effort to use them, ReactFX is not more glitch-free than RX (e.g. rxJava).

The techniques to eliminate glitches in ReactFX rely on the fact that event propagation is synchronous. On the other hand, event propagation in RX is always asynchronous, thus these techniques cannot be implemented in an RX system.

In the example above, we want to defer listener notifications until both sum and prod have been updated. This is how to achieve this with ReactFX:

import org.reactfx.Guardian;
import org.reactfx.inhibeans.binding.Binding;

IntegerProperty a = new SimpleIntegerProperty();
IntegerProperty b = new SimpleIntegerProperty();
Binding<Number> sum = Binding.wrap(a.add(b)); // Binding imported from ReactFX
Binding<Number> prod = Binding.wrap(a.multiply(b)); // Binding imported from ReactFX

InvalidationListener consistencyCheck = obs -> {
    assert sum.getValue().intValue() == a.get() + b.get();
    assert prod.getValue().intValue() == a.get() * b.get();
};

sum.addListener(consistencyCheck);
prod.addListener(consistencyCheck);

// defer sum and prod listeners until the end of the block
Guardian.combine(sum, prod).guardWhile(() -> {
    a.set(1);
    b.set(2);
});
Tomas Mikula
  • 6,537
  • 25
  • 39
  • 1
    Tomas, what do you mean by saying that event propagation in RX is always asynchronous ? As far as I know RX by default is single threaded, so how can it be always asynchronous? Could you please also give a specific example in RX (using a single thread ) where a glitch occurs? Am I mixing up the concepts of single threadedness and synchronicity? As far as I understand they are equivalent. Or not? – jhegedus Jan 24 '15 at 18:42
  • You mean by synchronicity atomicity? In other words, transactions? – jhegedus Jan 24 '15 at 18:45
  • Even though events in RX _may_ sometimes be propagated synchronously, Subscribers should never assume that and always treat events as asynchronous. I heard this from multiple sources, but I cannot find a citation right now. – Tomas Mikula Jan 25 '15 at 00:17
  • Single-threadedness is not a synonym for synchronicity. For example, if you call `Platform.runLater(runnable)` in JavaFX from the JavaFX thread, the `runnable` will be invoked on the same thread, but asynchronously (after the current event handler finishes). – Tomas Mikula Jan 25 '15 at 00:20
  • The consequence of asynchronicity is that by the time you receive an event, that event may not reflect the current state of the event's producer anymore (the producer may have changed state in the meantime). So there is _inconsistency_. In fact, there is _eventual consistency_. While eventual consistency is the only sane consistency requirement in a distributed setting, In an inherently single-threaded setting such as UI programming, we can get full consistency. I think this is what you mean by atomicity. – Tomas Mikula Jan 25 '15 at 00:30
  • All that said, even if you can get reliably synchronous event propagation in rxJava, you still need support to temporarily block event emission to avoid glitches. Just imagine a flow like this `-<>-` where data flows from left to right. A single event coming from left causes two events produced on the right (one when the top branch is propagated and one when the bottom branch is propagated), where the first event would be a glitch. – Tomas Mikula Jan 25 '15 at 00:52
  • [Related Discussion](https://social.msdn.microsoft.com/Forums/en-US/bc2c4b71-c97b-428e-ad71-324055a3cd03/another-discussion-on-glitches-and-rx?forum=rx). Note that a single observable in Rx *must always* propagate notifications serially per §4.2 [Rx Design Guidelines](http://go.microsoft.com/fwlink/?LinkID=205219); however, any given notification may in fact be observed concurrently with respect to the original producer. To introduce concurrency, typically a queue is inserted. The producer pushes notifications sequentially into the queue, and the consumer dequeues sequentially; e.g., ObserveOn – Dave Sexton Jan 25 '15 at 03:48
  • It's probably also worth noting that Rx offers a `CombineLatest` operator that is almost always used when trying to prove that "Rx causes glitches"; however, this is just one of many possible operators in Rx that have "combine latest" semantics. If you in fact needed different behavior, to the extent that it's possible in Rx, perhaps it could be implemented. I just think that people incorrectly assume that Rx is FRP, but it's not. – Dave Sexton Jan 25 '15 at 03:54
  • The `-<>-` example given by Tomas seems to be the same as given by Stephen Blackheath in this talk http://youtu.be/gaG3tIb3Lbk at 29th min. – jhegedus Jan 25 '15 at 12:14
  • Yep, his diagram just omits the left part. So Sodium gets you glitch-free behavior for free, as it analyzes and topologically sorts the directed acyclic graph of streams. In ReactFX you need some extra code to achieve this (in this case for the stream on the right to wait until it collects inputs from both branches). OTOH, the ReactFX way works even if the two inputs come from the outside world, in which case the FRP system has no way of knowing whether they change together or not; but the programmer knows. (I'm not saying that, in principle, you can't have both in one system; you could.) – Tomas Mikula Jan 25 '15 at 14:49
  • Tomas, what do you think of the simple 3 node graph example I gave in my answer (inspired by yours) ? Have I understood your answer correctly ? Is that really a glitch ? – jhegedus Jan 27 '15 at 14:34
4

Short answer : glitch = inonconsistent/illegal/meaningless state.

Here is a relevant link : https://social.msdn.microsoft.com/Forums/en-US/bc2c4b71-c97b-428e-ad71-324055a3cd03/another-discussion-on-glitches-and-rx?forum=rx

Also, see the 29th minute of Sodium's author talk for another answer : http://youtu.be/gaG3tIb3Lbk.

And a relevant SOF answer : how to avoid glitches in Rx

So here is my understanding of what a glitch is based on Tomas' answer.

There is a dataflow graph, with 3 nodes : A, B, C

A->B

A->C

In this simple example, a glitch happens if I change A and that causes to change B but C has not been updated yet. This is a glitch.

C is not consistent with B.

Say B=2*A, C=2*A.

Then if B is not equal C then that is a glitch.

Community
  • 1
  • 1
jhegedus
  • 20,244
  • 16
  • 99
  • 167
  • While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. – oɔɯǝɹ Jan 27 '15 at 14:29
  • Link is better than nothing. Right? – jhegedus Jan 27 '15 at 14:36
  • 4
    Not really. That's why link-only answer tend to get moderated away (there is a special category for link-only answers, as you may know). Good to see that you included some details in your answer though! – oɔɯǝɹ Jan 27 '15 at 14:39
  • Its really strange that everybody is talking about glitches but there seems to be no simple clear definition of it . – jhegedus Jan 27 '15 at 14:42
  • 1
    According to the definition given in my answer, this is a glitch _if_ someone is able to observe the intermediate inconsistent state. – Tomas Mikula Jan 27 '15 at 16:20
  • 1
    Excellent! I think I finally start to get it. Thanks for the patience! – jhegedus Jan 27 '15 at 19:00
3

Here is an extremely short and theoretical example of a fatal "glitch" situation in C# RX

var t = Observable
        .Interval(TimeSpan.FromSeconds(1))
        .Publish()
        .RefCount();

var s = t.CombineLatest(t, (t1,t2) => 1/(1-(t1-t2));

Since t1 and t2 both represent the latest value of the hot observable t, one would assume t1-t2 to always be 0. So s should always be 1.

But when subscribing to s, we indeed get 1 as the first observed value, but then we get a division by zero exception. In RxJS we would get NaN.

The reason is simple: a.CombineLatest(b, f) will react when either a or b produces a value, combining this new value and the last observed value of the other observable. This is by design, but from my experience, people using RX sometimes consider these to be glitches, especially when coming from other FRP libraries that have a different notion of "latest".

This is of course a contrived example, just meant to illustrate a misconception about CombineLatest.

Maybe CombineLatest should have been called WhenAny as in the ReactiveUI library, this would clarify the operational semantics?

Ziriax
  • 1,012
  • 10
  • 19
  • This isn't a glitch. This is exactly how the `CombineLatest` operator is meant to work. – Enigmativity Feb 18 '16 at 09:21
  • Got it. Could you give me an example of glitch in RX then? – Ziriax Feb 18 '16 at 11:54
  • This is the closest that I've seen to one - http://stackoverflow.com/questions/35417909/takeuntil-not-working-as-documented. Otherwise I've found it to be a pretty stable library. – Enigmativity Feb 18 '16 at 23:47
  • Thanks! But that sounds more like a bug than a glitch? Because it is very deterministic, that code always does the same thing, albeit wrong. But maybe a glitch is indeed a bug. I do not know, I always believed glitches were deterministic but undesired intermediate results. Maybe glitches will only truly exist when we get quantum computing? :-) – Ziriax Feb 19 '16 at 08:10
  • It seems the author of cycle.js also described glitches using combineLatest, see http://staltz.com/rx-glitches-arent-actually-a-problem.html – Ziriax Feb 19 '16 at 22:35
  • It's just one of those things when people make a naive assumption. The glitch is with the user's thinking not with the software's computation. – Enigmativity Feb 20 '16 at 02:12
  • 1
    This the exact definition of a "glitch" in reactive programming, which is a specific technical term. See https://en.wikipedia.org/wiki/Reactive_programming#Glitches – Kevin Borders Sep 25 '17 at 13:48
  • Well, then IMHO my example is a glitch, unless of course one exactly understands the order of subscriptions made by CombineLatest, but not many programmers will see it that way. I actually had glitches because of this where an intermediate rectangle with negative widths reached the UI layer (WPF in this case), and an exception was thrown. Of course the "final" rectangle was fine. – Ziriax Aug 26 '20 at 13:54