I think that "Mostly functional" is actually the sweet spot.
Going to any extreme makes some things horribly difficult and going to another does the same for other things. So, optimally, multiple paradigms coexist in the single codebase, applied where they're most useful.
Functional programming with as many immutable bits as possible is definitely a good start. I generally do that for whatever problem I'm solving: I have a model for the data and then I write (if at all possible) pure functions to transform the inputs into meaningful outputs. But then you need know where to drop the ball and move over to some other paradigm that does something else right and merely drives the functional parts from the top level.
For example, such a data analysis library can be written with minimal state and using only pure functions but if -- and when -- you need some sort of an user interface so that the program can actually be used, an imperative/procedural approach is generally the most native approach because UIs are basically I/O. If you're adding a graphical user interface, you might use object oriented approach to build the UI tree which is probably the world's most idiomatic, canonical use for OO anyway. But even those are generally driven with an innately imperative event loop.
Also, note that the different approaches or paradigms aren't language specific either.
In the first stage, languages are tools that shape your thinking into accepting new programming paradigms but at some point you have a number of different ways of thinking in your head, and you can just forget about the languages they came from.
But in the second stage, you can just think directly in paradigms: you can consider different ways to build different parts of your program but you might actually use only one language to implement everything. You can write functional, imperative, object-oriented, and whatever code in C. Or you can use several languages with strengths in each paradigm, depending on what trade-offs produce the best engineering in each case.
Please note that this is pretty much how you model Haskell programs as well: Keep as much of your logic as possible in pure code and interface/drive that with imperatively written stateful code. Purely functional languages (e.g. Haskell) do not remove your ability to code imperatively, they rather augment it so that you can better reason with it while doing it. Things like first class IO actions (that you can pass around) and explicitly marked state (i.e it's clear what you have in context and what you don't) make for some pretty satisfying solutions you wow yourself with.
It is common to hear in the Haskell community remarks like "Haskell is the best imperative language I've used."
I agree whole heartedly, people write some pretty impressive shared state concurrent programs in haskell, precisely because they know how much state is shared.
I agree. Part of the reason Clojure sees production use and Haskell does not leave its academic closet very often is that the former makes interaction with the non-functional parts of a system painless.
I don't regularly use either one, but I was under the impression that the situation is rather the reverse: Clojure is quite popular among hobbyists but doesn't get a lot of serious industry usage (perhaps excepting some stuff in the web space, which I don't really follow), while Haskell has a bunch of industry users. I see ads for Haskell jobs pretty often, anyway, while I'm not sure I've ever seen a Clojure job ad outside of HN threads.
My experience has been in the reverse, which just goes to show you how bad anecdotal evidence is at proving any point. Without any hard data, it's impossible to say for certain. All I know is that there is definitely enough demand for Clojure work that I didn't have to search for any leads when I left my last job; I already had four promising prospects to choose from that either emailed me directly or messaged me on Linkedin within the previous month.
I believe Haskell has deeper industry adoption than Clojure does right now. You just don't see it a lot because haskell people aren't as focused on evangelism.
I agree with you in general about 'mostly functional' being a sweet spot, but I think there's also lots of room for pure functions and immutability in ui programming without bending over backward too much.
For example, rather than creating a big oo hierarchy to model a ui, you can describe it declaratively as immutable data, then transform it with chains of pure and semi-pure functions whose only ultimate side effects are updating whatever bits of state absolutely must be held onto (ideally not much) and rendering the ui. I think that qualifies as 'mostly functional' even though it's not totally pure and doesn't use monads or other advanced constructs.
I haven't yet toyed with react.js, but I believe it takes an approach similar to this.
> So, optimally, multiple paradigms coexist in the single codebase, applied where they're most useful.
If you count a pure (e.g. monadic) encoding of another paradigm in this, then you're not disagreeing with Erik. If you don't, then I think you're wrong about where the sweet spot is.
Going to any extreme makes some things horribly difficult and going to another does the same for other things. So, optimally, multiple paradigms coexist in the single codebase, applied where they're most useful.
Functional programming with as many immutable bits as possible is definitely a good start. I generally do that for whatever problem I'm solving: I have a model for the data and then I write (if at all possible) pure functions to transform the inputs into meaningful outputs. But then you need know where to drop the ball and move over to some other paradigm that does something else right and merely drives the functional parts from the top level.
For example, such a data analysis library can be written with minimal state and using only pure functions but if -- and when -- you need some sort of an user interface so that the program can actually be used, an imperative/procedural approach is generally the most native approach because UIs are basically I/O. If you're adding a graphical user interface, you might use object oriented approach to build the UI tree which is probably the world's most idiomatic, canonical use for OO anyway. But even those are generally driven with an innately imperative event loop.
Also, note that the different approaches or paradigms aren't language specific either.
In the first stage, languages are tools that shape your thinking into accepting new programming paradigms but at some point you have a number of different ways of thinking in your head, and you can just forget about the languages they came from.
But in the second stage, you can just think directly in paradigms: you can consider different ways to build different parts of your program but you might actually use only one language to implement everything. You can write functional, imperative, object-oriented, and whatever code in C. Or you can use several languages with strengths in each paradigm, depending on what trade-offs produce the best engineering in each case.