|
1 | 1 | #  |
2 | 2 |
|
3 | | -C++React is reactive programming library for C++11. |
| 3 | +C++React is reactive programming library for C++14 that enables declarative definition of data dependencies between state and event flows. |
| 4 | +Based on these definitions, propagation of changes is handled automatically. |
4 | 5 |
|
5 | | -Generally speaking, it provides abstractions to handle change propagation and data processing for a push-based event model. |
6 | | -A more practical description is that it enables coordinated, multi-layered - _and potentially parallel_ - execution of callbacks. |
7 | | -All this happens implicitly, based on declarative definitions, with guarantees regarding |
| 6 | +Here's a simple example: |
8 | 7 |
|
9 | | -- _update minimality_ - nothing is re-calculated or processed unnecessarily; |
10 | | -- _glitch freedom_ - no transiently inconsistent data sets; |
11 | | -- _thread safety_ - no data races for parallel execution by avoiding side effects. |
12 | | - |
13 | | -The core abstractions of the library are |
14 | | - |
15 | | -- _signals_, reactive variables that are automatically re-calculated when their dependencies change, and |
16 | | -- _event streams_ as composable first class objects. |
17 | | - |
18 | | -Signals specifically deal with aspects of time-varying state, whereas event streams facilitate event processing in general. |
19 | | - |
20 | | -Additional features include |
21 | | - |
22 | | -- a publish/subscribe mechanism for callbacks with side effects; |
23 | | -- a set of operations and algorithms to combine signals and events; |
24 | | -- a domain model to encapsulate multiple reactive systems; |
25 | | -- transactions to group related events, supporting both synchronous and asynchrounous execution. |
26 | | - |
27 | | - |
28 | | -## Documentation |
29 | | - |
30 | | -[If you're interested in learning about C++React, have a look at its documentation.](http://schlangster.github.io/cpp.react/) |
31 | | - |
32 | | - |
33 | | -## Using the library |
34 | | - |
35 | | -This library is a work-in-progress. It should not be considered release quality yet and its API might still change. |
36 | | -It is, however, in a perfectly usable state and has already received a fair amount of testing and tuning. |
37 | | - |
38 | | -### Dependencies |
39 | | - |
40 | | -* [Intel TBB 4.2](https://www.threadingbuildingblocks.org/) (required) |
41 | | -* [Google test framework](https://code.google.com/p/googletest/) (optional, to compile the unit tests) |
42 | | -* [Boost 1.55.0 C++ Libraries](http://www.boost.org/) (optional, to include Reactor.h, which requires `boost::coroutine`) |
43 | | - |
44 | | -### Compiling |
45 | | - |
46 | | -C++React has been tested with the following compilers: |
47 | | - |
48 | | -* Visual Studio 2013.2 |
49 | | -* GCC 4.8.2 |
50 | | -* Clang 3.4 |
51 | | - |
52 | | -To build with Visual Studio, use the pre-made solution found in `project/msvc/`. |
53 | | - |
54 | | -To build with GCC or Clang, use [CMake](http://www.cmake.org/): |
55 | | -``` |
56 | | -mkdir build |
57 | | -cd build |
58 | | -cmake .. |
59 | | -make |
60 | 8 | ``` |
61 | | - |
62 | | -For more details, refer to the [Build instructions](https://github.com/schlangster/cpp.react/wiki/Build-instructions). |
63 | | - |
64 | | - |
65 | | -## Features by example |
66 | | - |
67 | | -### Signals |
68 | | - |
69 | | -Signals are self-updating reactive variables. |
70 | | -They can be combined in expressions to create new signals, which are automatically re-calculated when their dependencies change. |
71 | | - |
72 | | -```C++ |
73 | | -using namespace std; |
74 | 9 | using namespace react; |
75 | 10 |
|
76 | | -// Defines a reactive domain that uses single-threaded, sequential updating |
77 | | -REACTIVE_DOMAIN(D, sequential) |
| 11 | +void AddNumbers(int a, int b) { return a + b; } |
78 | 12 |
|
79 | | -// Defines aliases for types of the given domain, |
80 | | -// e.g. using VarSignalT<X> = VarSignal<D,X> |
81 | | -USING_REACTIVE_DOMAIN(D) |
| 13 | +// Two state variable objects. You can change their values manually. |
| 14 | +auto a = StateVar<int>::Create(0); |
| 15 | +auto b = StateVar<int>::Create(0); |
82 | 16 |
|
83 | | -// Two reactive variables that can be manipulated imperatively |
84 | | -// to input external changes |
85 | | -VarSignalT<int> width = MakeVar<D>(1); |
86 | | -VarSignalT<int> height = MakeVar<D>(2); |
| 17 | +// Another state object. Its value is calculated automatically based on the given function and arguments. |
| 18 | +// If the arguments change, the value is re-calculated. |
| 19 | +auto sum = State<int>::Create(AddNumbers, a, b); |
87 | 20 |
|
88 | | -// A signal that depends on width and height and multiplies their values |
89 | | -SignalT<int> area = MakeSignal( |
90 | | - With(width, height), |
91 | | - [] (int w, int h) { |
92 | | - return w * h; |
93 | | - }); |
| 21 | +// sum == 0 |
| 22 | +a.Set(21); |
| 23 | +// sum == 21 |
| 24 | +b.Set(21); |
| 25 | +// sum == 42 |
94 | 26 | ``` |
95 | | -Signal values can be accessed imperatively: |
96 | | -```C++ |
97 | | -cout << "area: " << area.Value() << endl; // => area: 2 |
98 | 27 |
|
99 | | -// Width changed, so area is re-calculated automatically |
100 | | -width.Set(10); |
| 28 | +The underlying system constructs a dependency graph to collect which values are affected by a change, and in which order they have to be re-calculated. |
| 29 | +This guarantees several properties: |
| 30 | +- _correctness_ - no updates are forgotten; |
| 31 | +- _consistency_ - no value is updated before all its incoming dependencies have been updated; |
| 32 | +- _efficiency_ - no value is re-calculated more than once per update cycle, and changes are only propagated along paths where a new value is different from the old one. |
101 | 33 |
|
102 | | -cout << "area: " << area.Value() << endl; // => area: 20 |
103 | | -``` |
104 | | - |
105 | | -Or, instead of using `Value()` to pull the new value, callback functions can be registered to receive notifications on a change: |
106 | | -```C++ |
107 | | -Observe(area, [] (int newValue) { |
108 | | - cout << "area changed: " << newValue << endl; |
109 | | -}); |
110 | | -``` |
111 | | -
|
112 | | -Overloaded operators for signal types allow to omit `MakeSignal` for a more concise syntax: |
113 | | -```C++ |
114 | | -// Lift as reactive expression - equivalent to previous example |
115 | | -SignalT<int> area = width * height; |
116 | | -``` |
117 | | - |
118 | | -### Event streams |
119 | | - |
120 | | -Unlike signals, event streams are not centered on changing state, but represent flows of discrete values. |
121 | | -They are first-class objects and can be merged, filtered, transformed or composed to more complex types: |
122 | | - |
123 | | -```C++ |
124 | | -using namespace std; |
125 | | -using namespace react; |
126 | | - |
127 | | -REACTIVE_DOMAIN(D, sequential) |
128 | | -USING_REACTIVE_DOMAIN(D) |
129 | | - |
130 | | -// Two event sources |
131 | | -EventSourceT<Token> leftClick = MakeEventSource<D>(); |
132 | | -EventSourceT<Token> rightClick = MakeEventSource<D>(); |
133 | | - |
134 | | -// Merge both event streams |
135 | | -EventsT<Token> anyClick = leftClick | rightClick; |
136 | | - |
137 | | -// React to events |
138 | | -Observe(anyClick, [] (Token) { |
139 | | - cout << "clicked!" << endl; |
140 | | -}); |
141 | | -``` |
142 | | -``` |
143 | | -leftClick.Emit(); // => clicked! |
144 | | -rightClick.Emit(); // => clicked! |
145 | | -``` |
146 | | -
|
147 | | -### Parallelism and concurrency |
148 | | -
|
149 | | -When enabling it through the concurrency policy, updates are automatically parallelized: |
150 | | -
|
151 | | -```C++ |
152 | | -REACTIVE_DOMAIN(D, parallel) |
153 | | -
|
154 | | -VarSignalT<int> in = MakeVar<D>(0); |
155 | | -
|
156 | | -SignalT<int> op1 = MakeSignal(in, |
157 | | - [] (int in) { |
158 | | - int result = doCostlyOperation1(in); |
159 | | - return result; |
160 | | - }); |
161 | | -
|
162 | | -SignalT<int> op2 = MakeSignal(in, |
163 | | - [] (int in) { |
164 | | - int result = doCostlyOperation2(in); |
165 | | - return result; |
166 | | - }); |
167 | | -
|
168 | | -// op1 and op2 can be re-calculated in parallel |
169 | | -SignalT<int> out = op1 + op2; |
170 | | -``` |
| 34 | +The system also knows when it's safe to update values in parallel from multiple threads, and it can do live profiling to decide when that's worthwhile. |
171 | 35 |
|
172 | | -## Acknowledgements |
| 36 | +## Development status |
173 | 37 |
|
174 | | -The API of C++React has been inspired by the following two research papers: |
| 38 | +I'm currently in the process of rewriting the library more or less from scratch and many things are still broken or outdated. |
175 | 39 |
|
176 | | -* [Deprecating the Observer Pattern with Scala.React](http://infoscience.epfl.ch/record/176887/files/DeprecatingObservers2012.pdf) |
177 | | -* [REScala: Bridging Between Object-oriented and Functional Style in Reactive Applications](http://www.stg.tu-darmstadt.de/media/st/research/rescala_folder/REScala-Bridging-The-Gap-Between-Object-Oriented-And-Functional-Style-In-Reactive-Applications.pdf) |
| 40 | +[The old, but stable and documented version is still available in this branch.](https://github.com/schlangster/cpp.react/tree/legacy1) |
0 commit comments