One thing that bugs me in the imperative vs. functional debate is that we (functional programmers) often show people a side-by-side comparison with 20 lines of imperative code, 6 lines of functional code, and say, see, the functional code is so much better! Well, to us, it is. Filtered through our biases, it's much more intuitive.
I think we're wrong on one thing. Personally, I think imperative code is more intuitive. It matches how people think of operational behaviors.
For a 20-line program that will never grow, I'd rather see an imperative straight-line solution. FP wins when things get a lot more complex: various special cases and loops within loops. Stateful things compose poorly. Debugging a 300-line inner for-loop is no fun. Functional programming, done right, means people factor long before it gets to that point.
Factories and Visitors prove what hellishness comes into being when one doesn't have those functional primitives, but this does not make the superiority of FP intuitive or obvious.
Now, OO is so variable in definition that it's very hard to know exactly what people mean. There's the good OOP (Alan Kay's vision; encapsulate complexity) and then there's bad OOP (overuse of inheritance, auto-generated classes, Factories and Visitors).
One can conceive of core.async as an OOP win in Clojure; lots of complexity (macroexpand a go block at some point) is being abstracted behind the simpler interface of a channel.
> Personally, I think imperative code is more intuitive. It matches how people think of operational behaviors.
The masses agree with you, apparently. That's why they sit in their cubes all day writing the same god damn re-implementation of map over and over again
List<String> result = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
result.add(input.get(i).toString());
}
I don't think recursion itself is difficult for most people to learn. The hard part is translating recursive functions into procedures. The imperative coding is what makes it confusing.
That's another problem with imperative programming; it tends toward DRY violations.
The solution using map is more intuitive, once you know what map is.
I agree with you, as well, that the functional style should be used far more often than is the case. I just think that one shouldn't assume that our way of doing things is inherently more intuitive, even if it is most often better.
The code that the functional programmer produces is a more direct expression of the programmer's thoughts. The author thinks "I want to map this list using this transformation" (although perhaps not in those exact words). The author is never thinking "I want to create a new list, then for each index between zero inclusive and the list size exclusive, apply this transformation, append the result to the list I created, and then jump back to the call site providing that list as a return value." The imperative programmer is first thinking functionally and then translating that thought into procedures instead of directly writing expressions that match the thought (and like you said, it's just because they haven't learned the word "map" yet). Isn't that pretty much the definition of "unintuitive"? First thinking one thing, and then requiring conscious effort to think another thing instead?
I think we're wrong on one thing. Personally, I think imperative code is more intuitive. It matches how people think of operational behaviors.
For a 20-line program that will never grow, I'd rather see an imperative straight-line solution. FP wins when things get a lot more complex: various special cases and loops within loops. Stateful things compose poorly. Debugging a 300-line inner for-loop is no fun. Functional programming, done right, means people factor long before it gets to that point.
Factories and Visitors prove what hellishness comes into being when one doesn't have those functional primitives, but this does not make the superiority of FP intuitive or obvious.
Now, OO is so variable in definition that it's very hard to know exactly what people mean. There's the good OOP (Alan Kay's vision; encapsulate complexity) and then there's bad OOP (overuse of inheritance, auto-generated classes, Factories and Visitors).
One can conceive of core.async as an OOP win in Clojure; lots of complexity (macroexpand a go block at some point) is being abstracted behind the simpler interface of a channel.