In computing, reactive programming is a declarative programming paradigm concerned with data streams and the propagation of change. With this paradigm, it is possible to express static (e.g., arrays) or dynamic (e.g., event emitters) data streams with ease, and also communicate that an inferred dependency within the associated execution model exists, which facilitates the automatic propagation of the changed data flow. Also has taxonomy of extant reactive programming approaches. General website on reactive programming, especially see the "general description".

For example, in imperative programming, a := b + c would mean that a is being assigned the result of b + c at the time the expression is evaluated, and later, the values of b and c can be changed with no effect on the value of a. In contrast, in reactive programming, the value of a is automatically updated whenever the values of b or c change, without the program having to explicitly re-state the statement a := b + c to re-assign the value of a. int b = 1; int c = 2; int a = b + c; b = 10; System.out.println(a); // 3 (not 12 because "=" is not a reactive assignment operator)

// now imagine a special operator "$=" exists that changes the value of a variable (executes code on the right side of the operator and assigns result to left side variable) whenever explicitly initialized, and when referenced variables (on the right side of the operator) are changed int b = 1; int c = 2; int a $= b + c; b = 10; System.out.println(a); // 12

Another example is a hardware description language such as Verilog, where reactive programming enables changes to be modeled as they propagate through circuits.

Reactive programming has been proposed as a way to simplify creating interactive user interfaces and near-real-time computing animation.

For example, in a model–view–controller (MVC) architecture, reactive programming can facilitate changes in an underlying model being reflected automatically in an associated view.

Approaches to creating reactive programming languages Several popular approaches are employed in creating reactive programming languages. One approach is the specification of dedicated languages that are specific to various domain constraints. Such constraints usually are characterized by real-time, embedded computing or hardware description. Another approach involves the specification of general-purpose languages that include support for reactivity. Other approaches are articulated in the definition, and use of programming libraries, or embedded domain-specific languages, that enable reactivity alongside or atop a programming language. Specification and use of these different approaches results in language capability trade-offs. In general, the more restricted a language is, the more its associated compilers and analysis programming tools are able to inform developers (e.g., in performing analysis for whether programs are able to execute in actual real-time). Functional trade-offs in specificity may result in deterioration of the general applicability of a language.

Programming models and semantics A variety of models and semantics govern reactive programming. They can be divided loosely along three dimensions: Synchrony – synchronous versus asynchronous model of time Determinism – deterministic versus non-deterministic evaluation process and results Update process – callback versus dataflow versus actor model

Implementation techniques and challenges Essence of implementations Reactive programming language runtimes are represented by a graph that identifies the dependencies among the involved reactive values. In such a graph, nodes represent the act of computing, and edges model dependency relationships. Such a runtime employs said graph, to help it keep track of the various computations, which must be executed anew, once an involved input changes value.

Change propagation algorithms Analogous to their low-level equivalents, the most common data propagation methods are: Pull – The value consumer is proactive, in that it regularly queries the observed source for values and reacts whenever a relevant value is available. Making this merely a new name for what has been called polling, and used in systems programming and hardware for a long time. Push – The value consumer receives a value from the source whenever the value becomes available. These values are self-contained, e.g., they contain all needed information, and no further information need be queried by the consumer. This is equivalent to callbacks. Push-pull – The value consumer receives a change notification, which is a short description of the change, e.g. "some value changed": this is the push part. However, the notification does not contain all the necessary information (which means it does not contain the actual values), so the consumer needs to query the source for more information (the specific value) after it receives the notification: this is the pull part. Making it also is merely a new name for what has been called interrupts and interrupt handlers in systems programming and hardware. This method is commonly used when there is a large volume of data that the consumers might be potentially interested in. So, to reduce throughput and latency, only light-weight notifications are sent; and then those consumers which need more information will request that specific information. This approach also has the drawback that the source might be overwhelmed by many requests for more information after a notification is sent.

What to push? At the implementation level, event reaction consists of the propagation across a graph's information, which characterizes the existence of change. Consequently, computations that are affected by such change then become outdated and must be flagged for re-execution. Such computations are then usually characterized by the transitive closure of the change (i.e., the full set of transitive dependencies a source affects) in its associated source. Change propagation may then lead to an update in the value of the graph's sinks.

Graph propagated information can consist of a node's complete state, i.e., the computation result of the involved node. In such cases, the node's previous output is then ignored. Another method involves delta propagation i.e. incremental change propagation. In this case, information is proliferated along a graph's edges, which consist only of deltas describing how the previous node was changed. This approach is especially important when nodes hold large amounts of state data, which would otherwise be expensive to recompute from scratch.

Delta propagation is essentially an optimization that has been extensively studied via the discipline of incremental computing, whose approach requires runtime satisfaction involving the view-update problem. This problem is infamously characterized by the use of database entities, which are responsible for the maintenance of changing data views.

Another common optimization is employment of unary change accumulation and batch propagation. Such a solution can be faster because it reduces communication among involved nodes. Optimization strategies can then be employed that reason about the nature of the changes contained within, and make alterations accordingly (e.g. two changes in the batch can cancel each other, and thus, simply be ignored). Yet another available approach, is described as invalidity notification propagation. This approach causes nodes with invalid input to pull updates, thus resulting in the update of their own outputs.

There are two main ways employed to build a dependency graph: The graph of dependencies are maintained implicitly within an event loop. Registration of explicit callbacks then results in creating implicit dependencies. Thus, control inversion, which is induced via callback, is thus left in place. However, making callbacks functional (i.e., returning state value instead of unit value) necessitates that such callbacks become compositional. A graph of dependencies is program-specific and generated by a programmer. This facilitates an addressing of the callback's control inversion in two ways: either a graph is specified explicitly (typically using a domain-specific language (DSL), which may be embedded), or a graph is implicitly defined with expression and generation using an effective, archetypal language.

Implementation challenges in reactive programming Glitches When propagating changes, it is possible to pick propagation orders such that the value of an expression is not a natural consequence of the source program. We can illustrate this easily with an example. Suppose seconds is a reactive value that changes every second to represent the current time (in seconds). Consider this expression:

t = seconds + 1 g = (t > seconds)

Because t should always be greater than seconds, this expression should always evaluate to a true value. Unfortunately, this can depend on the order of evaluation. When seconds changes, two expressions have to update: seconds + 1 and the conditional. If the first evaluates before the second, then this invariant will hold. If, however, the conditional updates first, using the old value of t and the new value of seconds, then the expression will evaluate to a false value. This is called a glitch.

Some reactive languages are glitch-free and prove this property. This is usually achieved by topologically sorting expressions and updating values in topological order. This can, however, have performance implications, such as delaying the delivery of values (due to the order of propagation). In some cases, therefore, reactive languages permit glitches, and developers must be aware of the possibility that values may temporarily fail to correspond to the program source, and that some expressions may evaluate multiple times (for instance, t > seconds may evaluate twice: once when the new value of seconds arrives, and once more when t updates).

Cyclic dependencies Topological sorting of dependencies depends on the dependency graph being a directed acyclic graph (DAG). In practice, a program may define a dependency graph that has cycles. Usually, reactive programming languages expect such cycles to be "broken" by placing some element along a "back edge" to permit reactive updating to terminate. Typically, languages provide an operator like delay that is used by the update mechanism for this purpose, since a delay implies that what follows must be evaluated in the "next time step" (allowing the current evaluation to terminate).

Interaction with mutable state Reactive languages typically assume that their expressions are purely functional. This allows an update mechanism to choose different orders in which to perform updates, and leave the specific order unspecified (thereby enabling optimizations). When a reactive language is embedded in a programming language with state, however, it may be possible for programmers to perform mutable operations. How to make this interaction smooth remains an open problem.

In some cases, it is possible to have principled partial solutions. Two such solutions include: A language might offer a notion of a "mutable cell". A mutable cell is one that the reactive update system is aware of, so that changes made to the cell propagate to the rest of the reactive program. This enables the non-reactive part of the program to perform a traditional mutation while enabling reactive code to be aware of and respond to this update, thus maintaining the consistency of the relationship between values in the program. An example of a reactive language that provides such a cell is FrTime.