Stephen Blackheath

Author
+ Follow
since Sep 25, 2016
Cows and Likes
Cows
Total received
5
In last 30 days
0
Total given
0
Likes
Total received
5
Received in last 30 days
0
Total given
1
Given in last 30 days
0
Forums and Threads
Scavenger Hunt
expand Ranch Hand Scavenger Hunt
expand Greenhorn Scavenger Hunt

Recent posts by Stephen Blackheath

Hi Krystian,

Thanks!

1. There's one chapter, Adding FRP to existing projects, that talks about the kinds of things that come up when you do this. It covers a range of common issues, but doesn't go into great depth.

2. The beginning of the book explains the basics of FRP, and the philosophy behind it, including the problems it solves and why it solves them. Most of the rest of the book is devoted to applying FRP in different kinds of situations/use cases, through examples.

3. Most of the examples are short, but there are 3 quite large examples: a. Petrol pump (chapter 4), b. Zombie game (chapter 7), and c. Fridgets, an FRP-based GUI system (chapter 12).

4. There is not much discussion about debugging. The book talks about how FRP code is inherently easy to unit test.



Steve
5 years ago
Hi Stephan,

Classic FRP is designed with an assumption that all values are associated with a time. In the terminology of Reactive Extensions, this means that it only has hot observables. At the time when you start using an FRP object, there is no access to anything from the past.

Reactive Extensions invented the idea of cold observables, that is, using an FRP-like interface to implement something equivalent to lazy lists in functional programming. FRP came from the world of functional programming, so it didn't need any of this because functional languages have lazy lists already.


Steve
5 years ago
Hi Sudd,

It depends somewhat on definitions, so maybe I'd be most accurate if I tried to summarize what FRP is: It's a functional "wrapping" of event-based logic. If you are used to the normal way of handling events, then a different way of thinking is required. In that respect, it's a different paradigm. It's not a programming language, but it definitely could be described as an EDSL - an embedded domain-specific language, meaning that it is embedded in a host language such as Java. The implementation is simply a small library.

1. The book starts off by explaining the basics of FRP and the thinking behind it, and then it gives examples of how to use it in a wide array of different cases. Each case is illustrated with an example. There are several quite large, involved examples. All the example code is at https://github.com/SodiumFRP/sodium/tree/master/book

The primary language is Java but there is a chapter devoted to Rx.JS and Javascript, mainly dealing with how to use Rx.JS to write FRP-style code.

2. How good a language is to implement FRP depends on what its syntax is like with typical FRP code - especially lambda syntax. Java, C#, Scala, Typescript and Haskell are all really good. Javascript and C++ are a bit clunky due to lambda syntax (Javascript) and type names (C++). Automatic memory management was a big challenge in Javascript/Typescript and C++ but this was recently solved.


Steve
5 years ago
Hi Enrique,

That problem is outside the scope of FRP.


Steve
5 years ago
Hi Stephan,

I haven't worked with Java streams but my understanding is that they don't function "asynchronously", by which I mean there is no way to merge the asynchronously occurring values of two streams into one. For example, let's say the values 1, 2, 3 appeared on stream sa. Presumably this limitation would mean that Java streams couldn't be used to implement, say, user interface logic. AFAIK you couldn't do the following in Java streams...



...with the result that sc will either output 1, 10, 2, 20, 3, 30, or it will output 10, 1, 20, 2, 30, 3, or something similar. Please correct me if I'm wrong. RxJava and Sodium both have this operation.

Sodium, being "true" FRP guarantees compositionality, while RxJava doesn't.

With RxJava you will get one of the two answers above, but which one is a matter of implementation detail, which is not specified.

The definition of compositionality is that the meaning of the composition depends only on the meaning of the components, and the rules used to combine them. Unspecified implementation details or other extraneous factors beyond that line of code have no effect.

In Sodium:
The meaning of sa is a stream of integers.
The meaning of sb is that it is identical to sa except for a modification of each value.
The rule "merge" says that the output stream will be based on the values of the two input streams, but in Sodium, there is a rule about what happens in the case where values are simultaneous. When at a given instant in time, only one of the streams produces a value, the output stream should simply output that value. But, Sodium makes the caller decide what to do in the simultaneous case. For example, we might add simultaneous numbers together:



The output would be 11, 22, 33.

Or, we could say that the value from stream a takes precedence:



The output would be 1, 2, 3. Sodium defines .orElse(..) as a shorthand for this common case.

Compositionality gives huge practical advantages and is easy to achieve in an implementation. Why wouldn't you want it? If you're going to build something huge, shouldn't it be on a solid foundation? I think the reason is that people don't understand the importance of compositionality.


Steve
5 years ago
Hi Thad,

Two-way binding would normally be modelled in FRP as a pair of a Stream<A> to allow changes to the widget - and a Cell<A> giving the current value of the widget. This would be true of a text field or similar widget. Essentially it's a function of this type (in Pseudo-Typescript):



The caller then represents the logic of the model as FRP, creating value loops as necessary. How difficult it is to get your head around actually using this depends to a large extent on how much functional programming you've done.


Steve
5 years ago
Hi Enrique,

In Functional Programming, mutable state is considered evil and is avoided.

In Functional Reactive Programming, mutable state is considered evil but is not avoided. Instead, it's put inside a little box called a Cell/Behavior/Property.

The singleton pattern doesn't really have a direct equivalent in FRP, because the singleton pattern would include an assumption that anyone can modify or read the global state of the instance. FRP would assume that the modifying and the reading of state are at least separate in some way. Can you make the question more concrete?


Steve
5 years ago
Hi Thad,

Yes and no.

First, there is now a Javascript version of Sodium, in case you are interested in trying that out: https://github.com/sodiumFRP/sodium-typescript

In a perfect world, you would like to write the code as if the asynchronous requests to the server foo(), bar(..) and baz(..) were able to block:



In more real world code there would be logic between these lines. Of course, there's no such thing as blocking I/O in Javascript so you can't do this directly.

FRP code ends up being structured in a more state machine-like "data flow" style, with nothing resembling a flow of control, so it doesn't allow you to write code in the style given above. If you're read chapter 13, you'll know what I mean about a "data flow" style. I/O is usually modelled as...



...where bar(..) is a function taking Stream<A> and returning Stream<B>. So you could write this code as:



sVar0 would be a stream of type Stream<Unit> and it would be needed to initiate the communications (assuming foo needs no input value). Now this does not handle errors, so you would need to add extra logic to deal with them. Picture it as a diagram with boxes and arrows - each async request having an "error" arrow coming out, like in chapter 13.

So this definitely can be done in FRP, but FRP is not as good for this kind of problem as the imaginary blocking I/O method described above. Given that this isn't available, it may still be a good option. Note that it is trivial to implement something equivalent to a promise in FRP.

Where FRP does really well is in situations with complex, multi-variable state machines - where all other approaches fail badly. (Video games and GUIs are good examples of this.) Your problem is basically a single variable state machine, where the variable is "where we are up to in the communications." In the blocking I/O model, this state variable is modelled as the current execution position in the flow of control.

I've got a chapter 10 Battle of the Paradigms that illustrates this point by comparing FRP against "actor model" which is really this flow of control style. The problem in this chapter is drag-and-drop again. There are some similarities between it and the I/O problem you presented.

In chapter 11 I deal with the question of asynchronous I/O more directly.


Steve
5 years ago
Thank you Henry, Campbell and Ganesh!
5 years ago
Hi Enrique,

The book defines the concept of a "true" FRP system, and one of the properties that comes from this definition is that it deals with concurrency automatically. The Sodium FRP system is the main example given of this, but any FRP system meeting this definition would have to also have this property.

There is a clear delineation between code that is FRP and code that is not FRP. Once a value is passed into the abstract world of FRP, concurrency issues completely disappear. This fact depends on certain rules being followed: Values must be immutable and closures must be referentially transparent. These rules are considered an absolute requirement in a true FRP system, and in return you get an absolute guarantee of no concurrency problems ever.

In a "non-true" FRP systems such as Reactive Extensions (Rx), these rules are not clearly defined, and so the situation is not nearly as nice.

The whole system is transactional, so that all state changes that result from a given input are atomic. When a value comes out of FRP logic as an output, it is then up to the programmer to deal with concurrency issues again. Sodium gives no guarantee of what thread a given callback will be on in this situation, so the code usually needs to delegate to another thread for processing.

The Sodium system does not currently implement true parallelism - and no FRP system does yet (to my knowledge), but this could be done without affecting the external interface of the library. The book talks briefly about some ways this might be achieved. There is one way in particular that would be very easy, and that is using a method called Software Transactional Memory (STM).


Steve
5 years ago
Hi Lanny,

You are essentially correct, except that "true" FRP includes one more element: It is mathematically compositional. This gives a big scalability advantage, in that the code doesn't become unmanageable as the size and complexity of the program increases. The book is largely about the different way of thinking involved in programming this way: viewing the program as a declarative description of the outputs in terms of the inputs.


Steve
5 years ago
Hi Campbell!

Reactive Programming is a broad term meaning that the program is event-based, viewed as a response to inputs, and viewed as a data flow.

Functional Reactive Programming is quite a lot more specific. It has the additional property that it is provably compositional, which means that the code stays manageable as the size of the program increases.


Steve
5 years ago