Ascending Functional Reactive Programming 6/7
Where is Functional Reactive Programming Now?
In the previous post of this series, we have reviewed some of the most noticeable academic works. In this post, we continue our survey of functional reactive programming usage in the professional world of client-side web applications. Of course, we keep our simplicity and unanimity criteria in the back of our mind.
Part 1/7 Why is Reactive Programming so Complicated?
Part 2/7 Functional Programming to the Rescue?
Part 3/7 Why is Functional Programming so Controversial?
Part 4/7 Functional Reactive Programming: Simple and Unanimous?
Part 5/7 How did Functional Reactive Programming Originate?
Part 6/7 Where is Functional Reactive Programming Now?
Part 7/7 Which Functional Reactive Programming is the Grail?
In the sections below, I will share with you a selection of JS frameworks I studied throughout my quest for simple unanimous functional reactive programming.
I will give a score from 0 to 10 for each of the following criteria: functional, reactive, simple and unanimous.
I will list the corresponding facts and thoughts, prefixed with “✅” when positive, “❌” when negative or “💡” when informational, to justify the score given to each framework.
Disclaimer:
I will not reiterate the disclaimer from my previous article (although it applies here too). However, I will add that I have selected a small number of candidates, rejecting others that were not sufficiently functional, reactive, simple nor unanimous.
So let us jump into the most awaited chunk of this series, I present to you… React!
1. React 28/40
React is a JavaScript library for building user interfaces.
Flux is the architecture recommended by React.
Redux is a JavaScript library for managing application state and is widely associated with React as an implementation of an enhanced variation of the Flux architecture.
React.useReducer is a React hook (available since React version 16.6), inspired by Redux reducers.
1.1. Functional 7/10
✅ React promotes functional programming.
❌ React, as a multi-paradigm library, gives the choice between functional style (stateless functional components) and object-oriented style (state-full class-based components). However, it is worth noting that Redux promotes functional programming, and nothing but functional programming.
✅ React is declarative.
✅ React offers higher-order components which are combinations of simple components (or other higher-order components) following the concept of higher-order functions.
✅ Redux reducers are composable functions.
✅ Flux architecture is an unidirectional data flow architecture, well suited for functional programming (influenced by The ELM Architecture seen earlier).
✅ Redux as well as React.useReducer is based on the functional programming concept of the reduce function.
❌ By default, React does not consider functional components as pure functions.
✅ If you choose the dark (object-oriented) side, React attempts to save your soul by making the state management of state-full class-based component (setState) asynchronous:
// this has no synchronously observable effect
this.setState({count:this.state.count++})
❌ I could not find a pure functional solution in React to the following classical problem: keep the cursor position of an input element while filtering out some of its characters.
💡 Using React.useReducer, I managed to prevent useless re-rendering of functional components, in a pure functional way (but not using Flux nor Redux architecture).
❌React hooks, the “modern” ways, are not functionally pure. One reason being their documented restrictions which are clearly not in adequacy with the referential transparency principle (a function should only have restrictions on the inputs passed to it, not the place where it is called).
1.2. Reactive 7/10
✅ As the name suggests, React is reactive indeed.
✅ Flux architecture may be considered as an implementation of the observer pattern allowing the user interface to react on state changes.
❌ React has a tight coupling between handlers and the view (event handlers are declared in the rendered HTML).
❌ Unless the programmer takes counter-measures, when an event occurs, all components are re-rendered even if they where not impacted by this event. For complex applications unnecessary re-renders may induce lags and impact the user interface reactivity.
❌ You need to carefully manage React hooks dependency arrays. Otherwise you might run into undesirable bugs (re-rendering too often or not re-rendering when needed).
1.3. Simplicity 7/10
💡 Although Redux model is simpler than Flux, requiring an additional library increases the complexity of writing programs (React.useReducer hook may be the right middle ground).
💡 React is based on some simple but numerous concepts (component, props, dispatcher, store, state, hooks, refs…).
❌ Redux requires a lot of boilerplate code, some say.
❌ React and its large ecosystem offer loads of alternatives (with their pros and cons) to do things, making a hard time for developers to choose from.
💡 In Flux, there is one dispatcher and several stores, whereas in Redux, there is only one (global) store, and no dispatcher.
💡 React recommends using the JSX syntax (a mix of JavaScript and XHTML) which simplifies the declaration of HTML rendering but requires a transpilation step (or TSX TypeScript equivalent).
1.4. Unanimity 7/10
✅ React is the most loved front-end framework for building client-side web applications (followed by Vue.js).
❌ React seems to be losing ground (on Vue.js) lately.
❌ Choosing the right state management tool is still under debate with Recoil gaining attention
💡 React is backed by Facebook.
💡 There has been some controversies about React licensing.
💡 Although it seems a wise design decision from the functional side, some (on the object-oriented side) complains that React component state management in React (setState) is asynchronous:
// this has no synchronously observable effect
this.setState({count:this.state.count++})
✅ React supports building mobile applications in addition to web applications.
❌ Using the Flux or Redux architecture, I could not find a way to prevent useless re-rendering of functional components, in a pure functional way (even after reading hundreds among thousands of blog posts).
2. Svelte 27/40
Svelte is a free and open-source front-end JavaScript framework.
Whereas traditional frameworks like React and Vue do the bulk of their work in the browser, Svelte shifts that work into a compile step that happens when you build your app.
2.1. Functional 4/10
✅ Svelte is highly declarative. Compared to Elm which is functional by nature: Elm is leaning more on the “how to do” compared to the straightforward and succinct Svelte version that lean on the “what to do”.
❌ Svelte author claims that there is an impedance mismatch between functional programming and web applications. He disapproves React postulate UI = F(STATE).
❌ Side effects such as DOM API calls can be done directly in Svelte scripts which goes against the purity principle of functional programming.
❌ Svelte implementation of reactivity is based on change detection which goes against the immutability principle of functional programming.
❌ Svelte is based on component composition. Note that component based architecture is valuable, nevertheless, component composition is not function composition.
❌ Svelte offers two-way binding. Here is an example of discussion where Svelte is considered less functional than React with Redux.
💡 Svelte is a compiler so the code does not produce any side-effects until it is compiled and executed.
2.2. Reactive 7/10
✅ Svelte author stresses the importance of reactive programming: “The essence of functional reactive programming is to specify the dynamic behavior completely at the time of declaration”.
✅ Svelte author demonstrates the UI responsiveness of Svelte compared to React.
✅ Svelte uses an optimized algorithm (topological ordering) for propagation of change.
❌ Svelte has some hacky ways to detect array mutations.
💡 Svelte does not support cyclical dependencies. Detecting cyclical dependencies may be considered either as a feature or as a limitation. The simple case of 3 interdependent edit-boxes, first name, last name and full name, cannot be implemented in Svelte. Here is a non-Svelte example in which cyclical dependencies are used to compute the convergence of a mathematical series.
❌ Cyclical dependencies cannot be dynamic since they are computed at compile time. Typically, you cannot implement a spreadsheet application in Svelte unless the compiler is included in the bundle.
2.3. Simplicity 8/10
✅ Svelte site gives access to a simple step by step interactive tutorial. Svelte learning curve is minimal.
✅ To add reactivity to a variable, simply add $: in front of the declaration or statement.
✅ Svelte source files look like HTML source files, including markup, CSS and script. Each source file implements a Svelte component.
❌ Svelte is not plain JavaScript and requires a compilation step.
2.4. Unanimous 7/10
✅ Svelte compiled applications are faster and have a smaller bundle size compared to traditional JavaScript runtime libraries, hence the name, Svelte.
❌ Svelte performance superiority is challenged by the author of a competitor UI library, SolidJS.
💡 Svelte has chosen its side in the ongoing dispute: no Virtual DOM.
❌ Svelte lacks TypeScript support because Svelte script is not exactly JavaScript, including specific DOM templating. For the same reason, standard refactoring tools do not fully work with Svelte (when it comes to rename a variable for instance).
✅ Svelte is fully featured, natively supporting animations (notably smooth visual transitions), component scoped CSS styles, state management, server-side rendering, mobile apps.
❌ Some argue that Svelte reactivity concept does not improve DX (Developer’s Experience). Notably, Svelte templating is criticized (“templates are not Turing-complete”) compared to React templating (JSX).
💡 Svelte is not (yet?) a major player but is gaining popularity as well as the idea behind it (compile step), not to mention his charismatic author, Rich Harris.
3. Observables and Streams (RxJS, Cycle.js) 34/40
The observer pattern is a design pattern in which the observable object notifies its observers of an event occurring. The observable object does not require the knowledge of what the observers ought to do on the occurrence of the event.
Streams extend the observer pattern to support sequences of data.
RxJS is the JavaScript implementation of ReactiveX, an API for asynchronous programming with observable streams.
Cycle.js is a framework based on streams. Its documentation coins observables and streams quite well.
3.1. Functional 8/10
✅ Programming with streams is declarative.
✅ Stream operators may be functionally composed.
❌ Streams themselves, being objects (with state), cannot be composed as functions.
3.2. Reactive 10/10
✅ Observables and streams are as close as it gets to what reactive is all about.
3.3. Simple 8/10
✅ A stream is a consistent abstraction. Every kind of reactivity source (user clicks, JavaScript generators, Ajax requests) may be modeled by a stream and described using the same API and operators.
✅ Streams abstract away concerns about things like low-level threading, synchronization, thread-safety, concurrent data structures, and non-blocking I/O.
❌ There are subtly non-obvious different kinds of streams (hot/cold, pull/push, lazy/eager…).
❌ At times, streams may block or overflow.
❌ Throttle and debounce (the stars of stream operator?) may be difficult to adjust.
✅ Reasoning about stream is easy, especially when drawing marble diagrams.
3.4. Unanimous 8/10
💡 There are loads of stream operators available out there.
💡 There are loads of stream libraries available out there.
✅ Programming with streams is far better than with Promise.
✅ Programming with Cycle.js is far better than React, for some.
✅ The latest version of Angular integrates RxJS (in an attempt to join the functional band wagon I assume).
❌ The inventor of Functional Reactive Programming, Conal Elliott, says that “Functional Reactive Programming… is certainly not about streams”.
4. Radioactive 18/40
Radioactive is a Native FRP (Functional Reactive Programming) environment for JavaScript.
4.1. Functional 5/10
✅ Radioactive claims to be a Functional Reactive Programming library.
❌ Radioactive samples seems rather procedural.
4.2. Reactive 7/10
✅ Reactivity is the main motivation for the author of the Radioactive library.
❌ Reactivity is impeded by the implementation decision to use blocking synchronous loops.
4.3. Simple 5/10
✅ The API is simple and has uniform syntax to declare data sources.
❌ The implementation is complex due to blocking synchronous loops simulating asynchronous reactivity.
4.4. Unanimous 1/10
❌The Radioactive library is not very popular right now.
❌The GitHub project stats are not terrific (the project has been untouched for 6 years).
✅ “Radioactive” is a pretty smart library name for Functional Reactive Programming enthusiasts.
❌ “Radioactive” is a pretty provocative library name for everybody else.
5. R Shiny 23/40
Shiny is an R package that makes it easy to build interactive web apps. R is a programming language for statistical computing.
5.1. Functional 5/10
❌ No explicit mention of functional programming.
❌ The programming style in the samples is not pure functional style, it is rather procedural with side-effects.
✅ R language is functional at its heart.
❌ Strictly speaking, R isn’t a functional programming language.
5.2. Reactive 8/10
✅ Shiny introduced the concept of “reactive value”.
✅ Shiny is designed for “interactive web apps”.
❌ Shiny host language R is not designed for “interactive web apps”.
5.3. Simple 5/10
✅ Lots of simple tutorials available.
✅ Procedural (oops, sorry, just kidding!).
❌ R is very different compared to JavaScript.
5.4. Unanimous 5/10
❌ Not implemented in JavaScript.
✅ R is popular in data-science and IA.
❌ Reference documentation difficult to find (no search box).
Should I care or should I not?
You definitely need to be aware of what the craze of the moment is although it might not be functional, reactive, simple nor unanimous. You also need to be aware that the craze of the moment might soon be outdated by the next ones.
You definitely need to be aware of what is out of fashion although it might be of little help for your legacy applications. Upgrading an application to a new framework or even a new version of the same framework is often an act of bravery.
Code your very own framework! JavaScript frameworks pop out like mushrooms so why not writing one too? At least be wise and code your applications with an abstraction layer around the one you choose! Watch out or one day this nice looking little beast will bite you where it hurts!
Well! this was a lot of information about a lot of functional reactive frameworks, selected among myriads of not so functional nor reactive others. React seems unescapable nowadays; compiled solutions such as Svelte are overtaking with a bold dive inside the bend; RxJS is well established with a firm theoretical background; esoteric asteroids are swooping close to planet JavaScript. Stay tuned for a wrap-up in the closing episode of this series and find out which functional reactive programming is the Grail.
Thanks
I would like to thank my father Micha who showed me that work can also be a passion (as well as a shelter) and my mother to whom I owe my self-confidence (towards computer science).