Lots of stuff now established as "best practices" or whatever in frontend JavaScript applications comes from being made popular with ClojureScript development. Side-effects as data, hot reloading, keeping your app state in one place all were inspired from work happening in the ClojureScript community at the time JavaScript community "discovered" it.
The ClojureScript community obviously didn't come up with everything, many of the ideas are very old ideas for UI development but didn't really exist in the "web-sphere" before. I'm pretty sure I can remember Dan Abramov saying Redux was directly inspired by stuff happening in the ClojureScript community, particularly around atoms and hot-reloading. Also I think Pete Hunt mentioned stuff David Nolen was working on when talking about React as well initially, but less confident about this.
I wouldn't be surprised if Redux has cross-polination from ClojureScript, but in terms of non-Javascript languages that inspired Redux, the top of that list is probably Elm.
Either way, FP is slowly eating the web. "View as function of state" has thoroughly won the argument. What that will ultimately look like is unclear, but ignore it at your own peril.
It’s not just eating the web, * as function of state is generally the trend in many disciplines. So much so that people I knew who balked at the concept have since embraced it. And it is good.
Now we just have to get a handle on all the leaky stuff at the edges of every “functional core”, because there lay many dragons.
I want this to be true. And certainly there has been a lot of progress towards functional-ish code in the languages I'm about to reference.
In my experience, languages like C, Go, Java, C# still dominate the backend. Replacing JavaScript is such a simple and well-defined task that I expect it will be completed much sooner. Maybe only a decade or two.
Well I can’t speak to most of those, but I can definitely speak to JS: pretty much the only things holding back FP are people’s aversion to reduce and their aversion to grafting monads where they don’t fit. Otherwise it’s pretty much idiomatic to write functional-core code in JS basically everywhere. But again there be dragons at the edges.
Like I said. Functional-ish. Still way too many ThingDoers and other associated boilerplate to be actually interesting. A nice option though if you're working in a legacy codebase or your employer requires it.
You describe an effect as a data structure which gets interpreted and applied by the appropriate driver (for the lack of a better term).
Think of how we do it on the wire: we send a description of a event (command/effect) to an API server which routes/dispatches it to something that applies an effect. It’s not a function call, but a generic (implementation agnostic) description of intent in pure data.
Is it kind of like events getting emitted and handled? I'm just a little fuzzy on what's creating the data/request/effect, and then where it's sending that once it's created, and then where the "drivers" would come from and how they would get invoked.
where it's sending that once it's created, and then where the "drivers" would come from and how they would get invoked
Depends on entirely on how you'd do it.
You can apply the Functional Core Imperative Shell architecture, where side-effecting, stateful code (imperative shell) always calls the functional code (functional core). The shell basically handles files, db connections, HTTP/TCP, exceptions, retries etc. and basically asks the functional core of what to do by providing the data that comes out of those things.
For example there's no reason a HTTP routing library has to do IoC. It can also be structured in a way so you you give it a path and it returns you data, such as an event description, a set of questions or a command description etc.
There are also frameworks that work this way, for example the UI state management framework re-frame. It handles the side effects for you and calls your functions that you register on certain UI events. The re-frame documentation is very good at explaining this step by step.
The side effect here is to a stop a running ticker on the page, but the `reg-event-fx` function just returns a map (data) where the first key is :db (which is the new app state, which is like a db, can even have a sorta schema over it) and the second key is the actual even :stop-ticker, which takes an argument handle (the handle of the ticker to stop).
The event handler is just describing the side effect that is to occur by returning the map.
BUt as far as testing goes, you can test the event handler and test that it returns the expected map. The framework is responsible for actually executing the event that is described the event handler and it does it via the name :stop-ticker. Your event handler itself can remain a pure function.
Instead of doing the side effect you return a description and let the framework handle it. E.g. you don't call `transact(db, data)` but return `["transact", db, data]`. Now your function is pure. The framework will expect you to provide the transact handler, e.g. as `register_handler("transact", (db, data) => {..})`.
Personally I'm not a fan of this abstraction (another layer of indirection). I'd rather take a `transact` function as an argument.
Comments
Lots of stuff now established as "best practices" or whatever in frontend JavaScript applications comes from being made popular with ClojureScript development. Side-effects as data, hot reloading, keeping your app state in one place all were inspired from work happening in the ClojureScript community at the time JavaScript community "discovered" it.
The ClojureScript community obviously didn't come up with everything, many of the ideas are very old ideas for UI development but didn't really exist in the "web-sphere" before. I'm pretty sure I can remember Dan Abramov saying Redux was directly inspired by stuff happening in the ClojureScript community, particularly around atoms and hot-reloading. Also I think Pete Hunt mentioned stuff David Nolen was working on when talking about React as well initially, but less confident about this.
I wouldn't be surprised if Redux has cross-polination from ClojureScript, but in terms of non-Javascript languages that inspired Redux, the top of that list is probably Elm.
See https://redux.js.org/understanding/history-and-design/prior-... which lists Elm right under Flux.
Either way, FP is slowly eating the web. "View as function of state" has thoroughly won the argument. What that will ultimately look like is unclear, but ignore it at your own peril.
It’s not just eating the web, * as function of state is generally the trend in many disciplines. So much so that people I knew who balked at the concept have since embraced it. And it is good.
Now we just have to get a handle on all the leaky stuff at the edges of every “functional core”, because there lay many dragons.
I want this to be true. And certainly there has been a lot of progress towards functional-ish code in the languages I'm about to reference.
In my experience, languages like C, Go, Java, C# still dominate the backend. Replacing JavaScript is such a simple and well-defined task that I expect it will be completed much sooner. Maybe only a decade or two.
Well I can’t speak to most of those, but I can definitely speak to JS: pretty much the only things holding back FP are people’s aversion to reduce and their aversion to grafting monads where they don’t fit. Otherwise it’s pretty much idiomatic to write functional-core code in JS basically everywhere. But again there be dragons at the edges.
Java and C# can absolutely be written in an FP style and it is definitely winning grounds.
Like I said. Functional-ish. Still way too many ThingDoers and other associated boilerplate to be actually interesting. A nice option though if you're working in a legacy codebase or your employer requires it.
My gut is telling me erlang might have tackled this.
Don't worry. It didn't.
surely "reducer" came from early FP leaks in mainstream
Can you give an example of what you mean by side effects as data?
You describe an effect as a data structure which gets interpreted and applied by the appropriate driver (for the lack of a better term).
Think of how we do it on the wire: we send a description of a event (command/effect) to an API server which routes/dispatches it to something that applies an effect. It’s not a function call, but a generic (implementation agnostic) description of intent in pure data.
It’s like that but inside your program.
Is it kind of like events getting emitted and handled? I'm just a little fuzzy on what's creating the data/request/effect, and then where it's sending that once it's created, and then where the "drivers" would come from and how they would get invoked.
Just a function.
Depends on entirely on how you'd do it.
You can apply the Functional Core Imperative Shell architecture, where side-effecting, stateful code (imperative shell) always calls the functional code (functional core). The shell basically handles files, db connections, HTTP/TCP, exceptions, retries etc. and basically asks the functional core of what to do by providing the data that comes out of those things.
For example there's no reason a HTTP routing library has to do IoC. It can also be structured in a way so you you give it a path and it returns you data, such as an event description, a set of questions or a command description etc.
There are also frameworks that work this way, for example the UI state management framework re-frame. It handles the side effects for you and calls your functions that you register on certain UI events. The re-frame documentation is very good at explaining this step by step.
SOmething like this:
The side effect here is to a stop a running ticker on the page, but the `reg-event-fx` function just returns a map (data) where the first key is :db (which is the new app state, which is like a db, can even have a sorta schema over it) and the second key is the actual even :stop-ticker, which takes an argument handle (the handle of the ticker to stop).The event handler is just describing the side effect that is to occur by returning the map.
ok so would it be correct to say this is sort of like handling an event that gets emitted?
Sorry, I know no clojurescript, so I'm having a hard time parsing it even googling the syntax
Yes, exactly.
There is a piece of code which emits the event :stop-timer, that stops a js timer in the window.
In clojure a map has the syntax So this event handler is returning a map which describes the event.There is then a further function which does the actual event
BUt as far as testing goes, you can test the event handler and test that it returns the expected map. The framework is responsible for actually executing the event that is described the event handler and it does it via the name :stop-ticker. Your event handler itself can remain a pure function.Instead of doing the side effect you return a description and let the framework handle it. E.g. you don't call `transact(db, data)` but return `["transact", db, data]`. Now your function is pure. The framework will expect you to provide the transact handler, e.g. as `register_handler("transact", (db, data) => {..})`.
Personally I'm not a fan of this abstraction (another layer of indirection). I'd rather take a `transact` function as an argument.