6 ms·
A General Theory of Reactivity
- yuchi 12y agoI found this read one of the most clear on the topic. I just made it almost mandatory in my team :)
- pron 12y agoAside from hijacking the term reactive-programming[1] (though it does give it a mention) this text repeats another mistake the Reactive Manifesto makes, namely confuse intent (or abstraction) with implementation. Even using the (quite unclear) hijacked definition of "reactive", there is absolutely nothing tying the goal of responsive programs to concepts such as asynchronous APIs, promises and observables. As an example, Erlang (and later Go) has been used to write "reactive" software with neither a hint nor a mention of callbacks, promises or observables (at least for the purposes outlined in this text). Those concepts are mere implementation tricks designed to circumvent blocking in environments that either don't have support for multi-threading at all (which makes blocking impossible if concurrency is to be maintained), or those where threads are necessarily kernel threads (where blocking entails a significant overhead). In fact, the whole notion of non-blocking is entirely accidental to the discussion of responsive/concurrent applications. Where lightweight threads are available (and, therefore, blocking is free), those design patterns are completely unnecessary for writing responsive software, and, in fact, make it quite cumbersome. Callbacks, promises and observables obliterate stack traces, make concurrency opaque, require explicit back-pressure as well as a complete "shadow" implementation of error handling and control structures beyond those provided by the language. They would all be considered anti-patterns[2] if they weren't a necessary last-resort workaround to the problem of expensive blocking (which happens to be not too hard to fix by other means). [1]: http://en.wikipedia.org/wiki/Reactive_programming http://en.wikipedia.org/wiki/Reactive_programming [2]: At least in non-pure languages. They do serve a purpose in referentially-transparent languages that don't have the concept of a stack or a thread, at least not in their common definition.
- deleted 12y ago[deleted]
- seanmcdirmid 12y agoIt seems to be more about ideology than theory, but theory is as overused as "reactive." React is a good example of a framework that lies outside of this: it is a simple solution for the problem that doesn't involve callbacks, promises, or even observables. My own project, Glitch, solves these problems by managing time: http://research.microsoft.com/en-us/people/smcdirm/managedtime.aspx http://research.microsoft.com/en-us/people/smcdirm/managedti... It doesn't block, it doesn't use functional abstractions either, Glitch simply replays code until all writes have seen all reads (it also doesn't requiring lifting of time-dependent values in the same way that React doesn't). Also, see: http://research.microsoft.com/pubs/230746/control.pdf http://research.microsoft.com/pubs/230746/control.pdf Which argues that we might have given up on control flow too soon. Still this isn't a bad essay for what it is, even if it isn't very general.
- pron 12y agoThose papers relate to real reactive programming (aka dataflow); the article discusses something else entirely, namely ways to write concurrent, low-latency, responsive applications. Unfortunately, it picks the more cumbersome approaches to achieve that goal.
- seanmcdirmid 12y agoYa, it is more systems than PL. See my reply to your other comment.
- cowbertvonmoo 12y agoYou are absolutely right that React accomplishes much without discrete event-driven change propagation. React falls clearly under the "behavior" style of reactivity, meaning that the state is polled to effect change. This is particularly useful in situations where change occurs more frequently than rendering, or even continuously. I talk about this toward the end of GToR.
- deleted 12y ago[deleted]
- tel 12y agoI'm just happy someone for one wrote one of these things and properly distinguished FRP as being different from "reactive programming" generally.
- pron 12y agoFRP is no more than reactive programming (sometimes known as dataflow programming) using a pure-functional programming style rather than an imperative style. It's just that the term "reactive programming" itself has been hijacked by some to mean something else entirely (roughly: concurrent, low-latency programs in general).
- seanmcdirmid 12y agoIf we go back to the 80s and the original reactive programming languages designed for embedded systems (which inspired FRP), we can see even more differences. In systems, there is a big push for (and against) "event-based programming" models with respect to concurrent and distributed systems; e.g. see: https://www.usenix.org/legacy/events/hotos03/tech/full_papers/vonbehren/vonbehren.pdf https://www.usenix.org/legacy/events/hotos03/tech/full_paper... where the definitions are even more different.
- pron 12y agoAh, yes. That paper (among other things) inspired me to implement true lightweight threads on the JVM. I also use some of the arguments in that paper to demonstrate that while pull and push are technically duals, in practice, pull APIs are always superior (except, again, in referentially transparent languages that lack the concept of a stack and a thread).
- seanmcdirmid 12y agoI've been writing.designing reactive programming languages and frameworks for more than 10 years now, I started out with Superglue in my dissertation: http://lampwww.epfl.ch/~mcdirmid/papers/mcdirmid06superglue.pdf http://lampwww.epfl.ch/~mcdirmid/papers/mcdirmid06superglue.... Early on, I realized that pull was the only safe/sane solution, so in all my languages (barring early versions of Superglue), change propagation merely dirties execution that could have read the changed value, which is queued to be re-executed and will pull the new value if it still depends on it. That is the style that I use for Glitch, and it has turned out to be very robust. Push is much harder. Actually, I'm not even sure how those systems even work properly; too many things to coordinate.
- liugiul 12y agoTo me, this seems pretty similar to Clojures lazy-seq. A seq is (afaik, I'm no expert Clojure guy although I enjoy it a lot) something with a 'next' value. A lazy seq basically can wait with returning the next object, and therefore be evaluated when it decides it's ready (like new data comes in, like a stream). Please let me know if I misunderstood this!!! As a someone who does JS for my day job I'm really enjoying playing with Clojure in my evenings and weekends (like now, it's Saturday night 00:30 here in Berlin). A small part of me dreams about doing it full time ;).
- astine 12y agoClose enough. A lazy sequence is a sequence who's elements are only generated when they're asked for. In Clojure, a sequence (seq) is a list datastructure. It can be traditional Lisp list, an array, or some other datastructure who's items are arrayed in an ordered sequence. You can generally treat a sequence like you can treat and array or a list in other languages accessing any element by its index, (except that it's immutable, of course.) Clojure doesn't traverse the sequence via 'next' unless the particular sequence type (ie a Lisp style list) is implemented to do it that way. A lazy sequence is a special kind of sequence which is implemented with a sort of 'cons' structure where the 'cdr' is a function to be called rather than a pointer. To clarify, in a traditional Lisp, a list is implement with a series of pairs of pointers called 'cons' cells. The first pointer is called the 'car' and it pointed to the content at that point in the list and the second pointer is called 'cdr' and it points to the next pair. A lazy sequence is similar except the that the pointer to the next pair is rather a function which returns the next pair. This means you can have a sequence who's actual data is not yet fulfilled. When you access an element in a lazy sequence, that element and every element before will be generated (and cached). Unless you access an element in that sequence, that element will never be generated. This lets you have things like infinite datastructures or do something like wrap a stream in a sequence and loop over it like it was an array. BTW, if your day job is with JS, maybe you can squeeze in a a ClojureScript app on a small project? I've done this.
- tunesmith 12y agoI immediately got hung up on the term "spatial" which has several concepts bolted onto it, while spatial is never defined. What do they mean by spatial?
- seanmcdirmid 12y agoJust a guess, but say you have an array of continuously changing values. What value you get out depends on index (spatial) and time (temporal) of the access. You could abstract over either: an index through iteration, and time through observation.
- visarga 12y agoThis reminds me of LazyJs. It also unifies many concepts under the same umbrella: arrays, dictionaries, strings, events - they could all be kinds of lazy sequences. Unifying so many things under the concept of lazy sequence gave me a wonderful feeling of insight.