HOME

TheInfoList



OR:

In
computing Computing is any goal-oriented activity requiring, benefiting from, or creating computing machinery. It includes the study and experimentation of algorithmic processes, and development of both hardware and software. Computing has scientific, ...
, reactive programming is a declarative
programming paradigm Programming paradigms are a way to classify programming languages based on their features. Languages can be classified into multiple paradigms. Some paradigms are concerned mainly with implications for the execution model of the language, suc ...
concerned with data streams and the propagation of change. With this paradigm, it's 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. For example, in an ''imperative'' programming setting, a := b + c would mean that a is being assigned the result of b + c in the instant the expression is evaluated, and later, the values of b and c can be changed with no effect on the value of a. On the other hand, 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-execute the statement a := b + c to determine the presently assigned value of a. Another example is a
hardware description language In computer engineering, a hardware description language (HDL) is a specialized computer language used to describe the structure and behavior of electronic circuits, and most commonly, digital logic circuits. A hardware description language en ...
such as
Verilog Verilog, standardized as IEEE 1364, is a hardware description language (HDL) used to model electronic systems. It is most commonly used in the design and verification of digital circuits at the register-transfer level of abstraction. It is als ...
, where reactive programming enables changes to be modeled as they propagate through circuits. Reactive programming has been proposed as a way to simplify the creation of interactive user interfaces and near-real-time system animation. For example, in a
model–view–controller Model–view–controller (MVC) is a software architectural pattern commonly used for developing user interfaces that divide the related program logic into three interconnected elements. This is done to separate internal representations of info ...
(MVC) architecture, reactive programming can facilitate changes in an underlying ''model'' that are reflected automatically in an associated ''view''..


Approaches to creating reactive programming languages

Several popular approaches are employed in the creation of reactive programming languages. 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 language A domain-specific language (DSL) is a computer language specialized to a particular application domain. This is in contrast to a general-purpose language (GPL), which is broadly applicable across domains. There are a wide variety of DSLs, ranging ...
s'', that enable reactivity alongside or on top of the 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 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. We can loosely split them along the following dimensions: * Synchrony: synchronous versus asynchronous model of time * Determinism: deterministic versus non-deterministic evaluation process and results * Update process: callback versus dataflow versus actor


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

The most common approaches to data propagation are: * Pull: The value consumer is in fact ''proactive'', in that it regularly queries the observed source for values and reacts whenever a relevant value is available. This practice of regularly checking for events or value changes is commonly referred to as ''polling''. * 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 the necessary information, and no further information needs to be queried by the consumer. * 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. This method is commonly used when there is a large volume of data that the consumers might be potentially interested in. So in order to reduce throughput and latency, only light-weight notifications are sent; and then those consumers which require more information will request that specific information. This approach also has the drawback that the source might be overwhelmed by many requests for additional 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 In mathematics, the transitive closure of a binary relation on a set is the smallest relation on that contains and is transitive. For finite sets, "smallest" can be taken in its usual sense, of having the fewest related pairs; for infinite ...
of the change 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 ''delta''s 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 Incremental computing, also known as incremental computation, is a software feature which, whenever a piece of data changes, attempts to save time by only recomputing those outputs which depend on the changed data. When incremental computing is s ...
, whose approach requires runtime satisfaction involving the view-update problem. This problem is infamously characterized by the use of
database In computing, a database is an organized collection of data stored and accessed electronically. Small databases can be stored on a file system, while large databases are hosted on computer clusters or cloud storage. The design of databases ...
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 principal ways employed in the building of a '' dependency graph'': # The graph of dependencies are maintained implicitly within an ''
event loop In computer science, the event loop is a programming construct or design pattern that waits for and dispatches events or messages in a program. The event loop works by making a request to some internal or external "event provider" (that generally ...
''. Registration of explicit callbacks, then results in the creation of implicit dependencies. Therefore, ''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 A domain-specific language (DSL) is a computer language specialized to a particular application domain. This is in contrast to a general-purpose language (GPL), which is broadly applicable across domains. There are a wide variety of DSLs, ranging ...
'' (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 In mathematics, particularly graph theory, and computer science, a directed acyclic graph (DAG) is a directed graph with no directed cycles. That is, it consists of vertices and edges (also called ''arcs''), with each edge directed from one ...
(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 "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. * Properly encapsulated object-oriented libraries offer an encapsulated notion of state. In principle, it is therefore possible for such a library to interact smoothly with the reactive portion of a language. For instance, callbacks can be installed in the getters of the object-oriented library to notify the reactive update engine about state changes, and changes in the reactive component can be pushed to the object-oriented library through getters. FrTime employs such a strategy.


Dynamic updating of the graph of dependencies

In some reactive languages, the graph of dependencies is ''static'', i.e., the graph is fixed throughout the program's execution. In other languages, the graph can be ''dynamic'', i.e., it can change as the program executes. For a simple example, consider this illustrative example (where seconds is a reactive value):
t =
  if ((seconds mod 2) 

0): seconds + 1 else: seconds - 1 end t + 1
Every second, the value of this expression changes to a different reactive expression, which t + 1 then depends on. Therefore, the graph of dependencies updates every second. Permitting dynamic updating of dependencies provides significant expressive power (for instance, dynamic dependencies routinely occur in
graphical user interface The GUI ( "UI" by itself is still usually pronounced . or ), graphical user interface, is a form of user interface that allows users to interact with electronic devices through graphical icons and audio indicator such as primary notation, ins ...
(GUI) programs). However, the reactive update engine must decide whether to reconstruct expressions each time, or to keep an expression's node constructed but inactive; in the latter case, ensure that they do not participate in the computation when they are not supposed to be active.


Concepts


Degrees of explicitness

Reactive programming languages can range from very explicit ones where data flows are set up by using arrows, to implicit where the data flows are derived from language constructs that look similar to those of imperative or functional programming. For example, in implicitly lifted
functional reactive programming Functional reactive programming (FRP) is a programming paradigm for reactive programming (asynchronous dataflow programming) using the building blocks of functional programming (e.g. map, reduce, filter). FRP has been used for programming gr ...
(FRP) a function call might implicitly cause a node in a data flow graph to be constructed. Reactive programming libraries for dynamic languages (such as the Lisp "Cells" and Python "Trellis" libraries) can construct a dependency graph from runtime analysis of the values read during a function's execution, allowing data flow specifications to be both implicit and dynamic. Sometimes the term ''reactive programming'' refers to the architectural level of software engineering, where individual nodes in the data flow graph are ordinary programs that communicate with each other.


Static or dynamic

Reactive programming can be purely static where the data flows are set up statically, or be dynamic where the data flows can change during the execution of a program. The use of data switches in the data flow graph could to some extent make a static data flow graph appear as dynamic, and blur the distinction slightly. True dynamic reactive programming however could use imperative programming to reconstruct the data flow graph.


Higher-order reactive programming

Reactive programming could be said to be of higher order if it supports the idea that data flows could be used to construct other data flows. That is, the resulting value out of a data flow is another data flow graph that is executed using the same evaluation model as the first.


Data flow differentiation

Ideally all data changes are propagated instantly, but this cannot be assured in practice. Instead it might be necessary to give different parts of the data flow graph different evaluation priorities. This can be called differentiated reactive programming. For example, in a word processor the marking of spelling errors need not be totally in sync with the inserting of characters. Here differentiated reactive programming could potentially be used to give the spell checker lower priority, allowing it to be delayed while keeping other data-flows instantaneous. However, such differentiation introduces additional design complexity. For example, deciding how to define the different data flow areas, and how to handle event passing between different data flow areas.


Evaluation models of reactive programming

Evaluation of reactive programs is not necessarily based on how stack based programming languages are evaluated. Instead, when some data is changed, the change is propagated to all data that is derived partially or completely from the data that was changed. This change propagation could be achieved in a number of ways, where perhaps the most natural way is an invalidate/lazy-revalidate scheme. It could be problematic simply to naively propagate a change using a stack, because of potential exponential update complexity if the data structure has a certain shape. One such shape can be described as "repeated diamonds shape", and has the following structure: An→Bn→An+1, An→Cn→An+1, where n=1,2... This problem could be overcome by propagating invalidation only when some data is not already invalidated, and later re-validate the data when needed using
lazy evaluation In programming language theory, lazy evaluation, or call-by-need, is an evaluation strategy which delays the evaluation of an expression until its value is needed ( non-strict evaluation) and which also avoids repeated evaluations (sharing). The ...
. One inherent problem for reactive programming is that most computations that would be evaluated and forgotten in a normal programming language, needs to be represented in the memory as data-structures. This could potentially make reactive programming highly memory consuming. However, research on what is called ''lowering'' could potentially overcome this problem. On the other side, reactive programming is a form of what could be described as "explicit parallelism", and could therefore be beneficial for utilizing the power of parallel hardware.


Similarities with observer pattern

Reactive programming has principal similarities with the
observer pattern In software design and engineering, the observer pattern is a software design pattern in which an object, named the subject, maintains a list of its dependents, called observers, and notifies them automatically of any state changes, usually by ca ...
commonly used in
object-oriented programming Object-oriented programming (OOP) is a programming paradigm based on the concept of "objects", which can contain data and code. The data is in the form of fields (often known as attributes or ''properties''), and the code is in the form of ...
. However, integrating the data flow concepts into the programming language would make it easier to express them and could therefore increase the granularity of the data flow graph. For example, the observer pattern commonly describes data-flows between whole objects/classes, whereas object-oriented reactive programming could target the members of objects/classes.


Approaches


Imperative

It is possible to fuse reactive programming with ordinary imperative programming. In such a paradigm, imperative programs operate upon reactive data structures.. Such a set-up is analogous to imperative constraint programming; however, while imperative constraint programming manages bidirectional data-flow constraints, imperative reactive programming manages one-way data-flow constraints.


Object-oriented

Object-oriented reactive programming (OORP) is a combination of object oriented programming and reactive programming. Perhaps the most natural way to make such a combination is as follows: instead of methods and fields, objects have ''reactions'' that automatically re-evaluate when the other reactions they depend on have been modified. If an OORP language maintains its imperative methods, it would also fall under the category of imperative reactive programming.


Functional

Functional reactive programming (FRP) is a programming paradigm for reactive programming on
functional programming In computer science, functional programming is a programming paradigm where programs are constructed by applying and composing functions. It is a declarative programming paradigm in which function definitions are trees of expressions tha ...
.


Actor based

Actors have been proposed to design reactive systems, often in combination with Functional reactive programming (FRP) to develop distributed reactive systems...


Rule based

A relatively new category of programming languages uses constraints (rules) as main programming concept. It consists of reactions to events, which keep all constraints satisfied. Not only does this facilitate event-based reactions, but it makes reactive programs instrumental to the correctness of software. An example of a rule based reactive programming language is Ampersand, which is founded in
relation algebra In mathematics and abstract algebra, a relation algebra is a residuated Boolean algebra expanded with an involution called converse, a unary operation. The motivating example of a relation algebra is the algebra 2''X''² of all binary relations ...
..


Implementations

*
ReactiveX ReactiveX (also known as Reactive Extensions) is a software library originally created by Microsoft that allows imperative programming languages to operate on sequences of data regardless of whether the data is synchronous or asynchronous. It pro ...
, an API for implementing reactive programming with streams, observables and operators with multiple language implementations including RxJs, RxJava, Rx.NET, RxPy and RxSwift. *
Elm (programming language) Elm is a domain-specific programming language for declaratively creating web browser-based graphical user interfaces. Elm is purely functional, and is developed with emphasis on usability, performance, and robustness. It advertises "no runtim ...
Reactive composition of web user interfaces. * Reactive Streams, a JVM standard for asynchronous stream processing with non-blocking backpressure
ObservableComputations
a cross-platform .NET implementation. *
Svelte Svelte is a free and open-source front end component framework or language created by Rich Harris and maintained by the Svelte core team members. Svelte is not a monolithic JavaScript library imported by applications: instead, Svelte compiles H ...
, brings reactivity in the form of a variant
JavaScript syntax The syntax of JavaScript is the set of rules that define a correctly structured JavaScript program. The examples below make use of the log function of the console object present in most browsers for standard text output. The JavaScript stan ...
that looks like
JavaScript JavaScript (), often abbreviated as JS, is a programming language that is one of the core technologies of the World Wide Web, alongside HTML and CSS. As of 2022, 98% of websites use JavaScript on the client side for webpage behavior, of ...
but is naturally reactive where JavaScript normally isn't.
Solid.js
brings reactivity to
JavaScript JavaScript (), often abbreviated as JS, is a programming language that is one of the core technologies of the World Wide Web, alongside HTML and CSS. As of 2022, 98% of websites use JavaScript on the client side for webpage behavior, of ...
without changing
JavaScript syntax The syntax of JavaScript is the set of rules that define a correctly structured JavaScript program. The examples below make use of the log function of the console object present in most browsers for standard text output. The JavaScript stan ...
semantics, along with reactive JSX templating.


See also

* Observable (Computing), observable in reactive programming.


References


External links

{{External links, date=August 2016
A survey on reactive programming
A 2013 paper by E. Bainomugisha, A. Lombide Carreton, T. Van Cutsem, S. Mostinckx, and W. De Meuter that surveys and provides a taxonomy of existing reactive programming approaches.

a general site about reactive programming.
Deprecating the Observer Pattern
A 2010 paper by Ingo Maier, Tiark Rompf and
Martin Odersky Martin Odersky (born 5 September 1958) is a German computer scientist and professor of programming methods at École Polytechnique Fédérale de Lausanne (EPFL) in Switzerland. He specializes in code analysis and programming languages. He designe ...
outlining a reactive programming framework for the Scala programming language.
Deprecating the Observer Pattern with Scala.React
A 2012 paper by Ingo
RxJS
the Reactive Extensions library for "composing asynchronous ..programs using observable sequences"
Tackling the Awkward Squad for Reactive Programming: The Actor-Reactor Model
A 2020 paper that proposes a model of "actors" and "reactors" to avoid the issues that arise when combining imperative code with reactive code. Programming paradigms Evaluation strategy