3 ms·
I think this is a wonderful idea and one of the best ways to structure software, but I want to point out that the functional core is only one way to achieve the
by sirwhinesalot 4y ago
I think this is a wonderful idea and one of the best ways to structure software, but I want to point out that the functional core is only one way to achieve the benefits and if you are in an environment where that is not possible due to performance or whatever, you can still derive most of the benefits by focusing on the state transformation part.
The real key aspect of this approach is that your state is not spread around the code and changing all over the place, but instead a big State -> State function built out of many smaller referentially transparent functions. (i.e. the complete opposite of OO programming, which IMO is a generally terrible idea that only works well in Smalltalk or in distributed systems).
You can achieve a similar outcome in the procedural setting with a "double buffered" state. Your procedural function writes out a new state based on the previous state, and the "imperative shell" only ever touches the "completed" states, and then flips them so the current state becomes the previous state and the previous state becomes the buffer to have the new state written into.
Less convenient but if you need to have tight control over memory allocations or performance this can be beneficial.
- dgb23 4y agoConceptually this reminds me a bit of a ring buffer, which also deals with the issue of having to manage a fixed size memory allocation. Or a draft/publish workflow where you’re constantly re-use memory instead of remembering published documents. I like it! It’s clever and seems to be generally applicable. Is there a name for it?
- sirwhinesalot 4y agoThere's probably a name, but I don't know it, I saw the idea somewhere before but can't remember where.
- geokon 4y agoThe issue is that while this greatly simplifies the program logic, when you start to scale the application you do end up with a lot of redundant computation. So in the end you need to either: . take a performance hit . somehow track/update costly intermediaries in your global state, and this can balloon out of control really fast . pair it with some memoization mechanism/framework that automatically manages "derived state" variables
- sirwhinesalot 4y agoYup, and I strongly suggest option 1, just take the perf loss. You can probably detect in each of your state update functions that nothing changed and just reuse the previous result (a memcpy is pretty fast, or if that data is in a separate allocation just copy the pointer). The same is true of the functional core idea really, you're still going to have a big tree of function calls rebuilding things unless you also add some memoization to it. React and friends do it because DOM manipulation is very slow. But think of IMGUI style GUIs, they're rebuilding the entire user interface every frame and yet are often more efficient than many retained mode UIs. Redundant computation is not as bad as it sounds at first glance.
- geokon 4y agoI asked around and there is another option. Something called "Incremental Computations". Here is a Clojure library. I think the examples kinda demo how it works https://github.com/hoplon/javelin https://github.com/hoplon/javelin It's sort of a version of option 3
- kaba0 4y ago> and yet are often more efficient than many retained mode UIs I don’t know what metric you use for that, but they are definitely not more energy efficient — retained mode is a must for any battery-powered device.
- sirwhinesalot 4y agoI meant computational efficiency, highly dynamic UIs usually perform a lot better as immediate mode GUIs since there are less indirections and memory allocations going around. If you're rebuilding things a lot anyway, it's actually more efficient to just accept that rather than work around it. Though speaking of immediate mode UIs, I think a lot of the problem there is that most of the immediate mode UI libraries assume they're being used as the user interface of a Game or 3D render application which needs to render a complex 3D scene regardless, so who cares about the extra 400 microseconds the UI takes to render. You could imagine optimizing immediate mode UIs quite a bit for energy efficiency by not redrawing anything if there's no use input, or selectively redrawing dirty areas where it makes sense.