|
I've been primarily a professional Clojure developer for several years, that's how I earn my living, and thus I have used the language in many contexts. In the beginning I was in love with it, in hindsight at least part of this love was the thrill of doing something new. But my appreciation for that style of programming has gradually declined over the last 5 years. FP is great for many little things you might have to do. But for larger architectural considerations, I still find notable advantages to creating custom classes that have their own public API, private internal implementation, and that manage their state internally. In the absence of this, you have lots of functions that are basically sitting alone with their pure inputs and outputs, and to manage state requires more effort, not less, in a lot of situations. Each of these functions has to receive the thing they are acting on, and a separate group of functions manages the actual mutation, acting as "controllers" between these more pure functions and the actual stored state. The result is a less elegant program structure sometimes. FP enthusiasts like to say that "it's better for many functions to operate on common data structures than it is to have many custom data structures with their own functions." The problem in my experience is that often, these pure functions are only serving one purpose geared for a particular data layout, and thus they might as well be coupled to it; the lack of a backbone in larger FP architectures can be frustrating. In Clojure, you have maps, and all maps behave the same. Great. But not all maps are actually the same. Each map ultimately has its own structure, and these functions that operate on a particular map are really operating on a particular structure a lot of the time. So you end up with increased verbosity and more difficult-to-follow code structure than if you just combined the data and its functions in one place: a class. The record-protocol idea attempts to alleviate this, but I don't feel it really gets to the heart of the issue. I think OO and FP each solve problems in equally meaningful ways and different tasks are better suited to one or the other. I particularly like languages that don't force you into a particular model. Java and Clojure are quite opinionated (in opposite ways) and thus often inflexible for certain tasks. My favorite language for blending these techniques has become C++ but I don't get to use it as much. It offers true FP-style programming with constructs like std::function. I wish Java had gone as far as C++11 did; the Java lambdas and the requirement that they can only be type defined using a static interface is not really helping to adopt the paradigm. |
In OCaml, you usually do that with modules. For instance, you can easily write mutable or immutable datatypes that hide their internal representation.
> My favorite language for blending these techniques has become C++
I also like programming languages that embrace several paradigms. The problem with C++ is that it's a very complex language. Compared to C++, OCaml is a piece of cake.