4 ms·
While this may be technically sound, I think this is not the most fundamental way of explaining FRP. FRP is just a toy really. It's a useful toy that help to gr
by quadcore 9y ago
While this may be technically sound, I think this is not the most fundamental way of explaining FRP. FRP is just a toy really. It's a useful toy that help to grasp and use an advanced programming concept. Let me explain.
That concept originates from a common programming mistake. A common mistake is to use compulsive caching. It's the tendency to store function results in a variable just because this result is gonna be re-used. The right way instead is to evaluate (or "re-evaluate") the function every time you need it unless you have a good reason not to (the only good reason is that the function is a bottleneck that affects the experience of the user). This is a better way of doing things because as everybody knows, invalidating caches is a hard thing to do (and variables, guess what, are just caches).
The added benefit (which really is not a benefit, but just good programming) is that things gonna now seem reactive.
- platz 9y agoYour world does not address the difficulties of dealing with shared state and coordination, which is what FRP addresses in a principled way. FRP means you don't have data races on checking global variables and events littered all throughout the program, firing and mutating in an order that must be considered effectively random.
- raquo 9y agoThis "assignment is caching is bad" analogy does not hold any water. You get a result from a call to `foo(bar)`. You have to _do something_ with that result. One common thing you'd need to do is to call another function: _baz(foo(bar))_. But then you're just hiding the assignment inside a baz function call (the result of _foo(bar)_ will be available as a variable/constant inside of _baz_). That doesn't so bad if you only need to do one thing with with the result of `foo(bar)`. Now what if you have to do something with that result twice. In this case all you've done is reduce the scope of a constant to be smaller than it needs to be, requiring you to make a duplicate `foo(bar)` call. Now you're repeating yourself and you don't know anymore if you're conceptually dealing with the same result or if foo(bar) might produce a different result on second call. You removed philosophical/semantic meaning from your code and did not gain anything from it. If you find yourself wanting/needing to "expire" variables that you define before you run out of scope, then the answer is a combination of: 1) use constants of immutable data structures, not variables or mutable structures 2) better name such constants so that you know what they represent 3) better manage scope and function size In practice, the above is much easier to achieve than what you're proposing, and makes the code easier to read and maintain. > The right way instead is to evaluate (or "re-evaluate") the function every time you need it unless you have a good reason not to (the only good reason is that the function is a bottleneck that affects the experience of the user) That does not scale to using the coding paradigm that you're proposing application-wide. Your whole app will be one big bottleneck because it's doing a multiple of the computations that it needs to be doing, with no easy way out. I guess you can get away with that by throwing more money at your backend infra, but you can't do that on mobile or for web frontends or desktop apps.
- naasking 9y ago> You get a result from a call to `foo(bar)`. You have to _do something_ with that result. One common thing you'd need to do is to call another function: _baz(foo(bar))_. But then you're just hiding the assignment inside a baz function call (the result of _foo(bar)_ will be available as a variable/constant inside of _baz_). Unless the OP is arguing for call-by-name evaluation, which when you take his words literally, sounds like exactly what he's arguing for.