6 ms·
Your examples are inherently functional, and in practice people would do ABCDService that just returns the result. But ignoring that - how is the code changing
by ajuc 2y ago
Your examples are inherently functional, and in practice people would do ABCDService that just returns the result. But ignoring that - how is the code changing when you need to call some external API from the c(x) function and handle the credentials, session, errors etc? Real world has external state and we do need to work with it.
> you shouldn't be programming with state ever if you're doing FP. You need to segregate state away from your program as much as possible. State by nature is hard to modularize. State should be very simple generic mutation operations like getValue and setValue, it should rarely ever contain operational logic.
This approach to state management is exactly what is causing the need to rewrite almost everything when requirements change in a functional program.
I like how clean FP code is when it's done. But I hate writing FP code when I'm not 100% sure what needs to be done and what might change in the future. If I could write imperative code with side effects and once I'm done have it transpiled into efficient, elegant, minimized state functional code - that would be great. Maybe it will happen at some point with AI getting better.
- ninetyninenine 2y ago> Your examples are inherently functional, and in practice people would do ABCDService that just returns the result. But ignoring that - how is the code changing when you need to call some external API from the c(x) function and handle the credentials, session, errors etc? Real world has external state and we do need to work with it. Abcdservice is bad because I want to use a b c and d in different contexts. You’re saying in the real world oop promotes a style where you can’t break down your code into legos. With oop you need to glue a b c and d together. My code is not inherently functional. I literally picked the smallest possible logical operations and interpreted them as either functional or oop. And then I tried to compose the logical operations. I mean look at it. A b and c are just one or two mathematical operators. If you’re saying this is inherently functional then your saying computing at its most primitive state is inherently functional. > This approach to state management is exactly what is causing the need to rewrite almost everything when requirements change in a functional program. Not true. Fp programs segregate state. Look at my code. All the code for fp is stateless. The only state is y=1. > But I hate writing FP code when I'm not 100% sure what needs to be done and what might change in the future. You hate what’s inherently better for the future. Fp is more modular and therefore more adaptable for the future. You hate it because you don’t get it.
- ajuc 2y ago> If you’re saying this is inherently functional then your saying computing at its most primitive state is inherently functional. Sure. But computing isn't what most code does. > Fp is more modular and therefore more adaptable for the future That is wrong. It's cleaner to read, but it usually requires more lines of code to be changed when requirements change - so it's less adaptable. Before changes FP: y = 1 a = (x) => x + 1 b = (x) => x \* 2 c = (x) => x \* x d = (x) => x - 4 f = a . b . c . d result = f(y) ugly imperative code: y = 1; void doABCD() { y += 1; y *= 2; y *= y; y -= 4; } Now you want to count how many times you squared numbers larger than 1000. FP: y = [1, 0] a = (x) => [x[0] + 1, x[1]] b = (x) => [x[0] \* 2, x[1]] c = (x) => [x[0] \* x, x>1000 ? x[1]+1 : x[1]] d = (x) => [x[0] - 4, x[1]] f = a . b . c . d result = f(y) imperative: y = 1; count = 0; void doABCD() { y += 1; y *= 2; if (y > 1000) count ++; y *= y; y -= 4; } Total lines changed in FP - all except 2. Total lines changed in imperative - 3. Of course you can refactor the FP version to split the part that requires the new state from the other parts. But in any big program that refactor is going to be PITA. Do you get my point now? I'm not saying imperative is better. It is ugly. But it's faster to adapt to the new requirements.
- ninetyninenine 2y agoNo way. Imperative is worse. You're just not using FP correctly. You're trying to do something monadic which is something I would avoid unless we absolutely need an actual side effect. y = 1 a = (x) => x + 1 b = (x) => x \* 2 c = (x) => x \* x d = (x) => x - 4 f = a . b . c . d result = f(y) You're doing the refactor wrong let me show you. You have to compose new pipelines that reveal the intermediate values. count = 0 firstPart = a . b secondPart = c . d countIfGreaterThan1000 = (x, prevCount) => x > 1000 ? prevCount + 1 : prevCount n = firstPart(y) newCount = countIfGreaterThan1000(n, count) result = secondPart(n) The key here isn't the amount of lines of code. The key here is to see that under FP the original code is like legos. If you want to reconfigure your fundamental primitives you just recompose it into something different. You don't have to modify your original library of primitives. With OOP you HAVE to modify it. doABCD() can't be reused. What if I want something additional (doABCD2) that does the EXACT same thing as doABCD() but now without counting the amount of times something was squared and greater than 1000 but now instead I want it for the amount of times the total was greater than 3? You can't reconfigure the code. You have to duplicate the code now. Basically you have to imagine functional programming as pipelines. If you want to add something in the middle of the pipeline, you cut the composition in half and split the pipe. One pipe goes towards the end result of what d outputs and the other pipe goes towards countGreaterThan1000