ugh, really sick of this meme. OO is a tool in the box, it's useful a lot of the time, sometimes it isn't. The reason ES6 introduces the `class` keyword is that people are doing that already.
I somewhat agree, but "adding tools" at the language level doesn't come for free: it causes an explosion in the number of interactions to keep track of. How do classes interact with prototypes? How do they interact with lexical scope? How do they interact with exceptions? etc.
The egregious part is that, by turning something into a language feature, those who don't use it are often forced to take it into account in their code; especially library authors.
About the only thing that might be interesting to see is how constructor parameters are handled. With the prototyping system, I consider it to be a bug to initialize members in the constructor - if you always just call an 'init' method straight after construction (typically chained, much like in Objective C - var thing = new Thing().init(param); ) then protyping is very simple and does nothing surprising. It's only if you really really really want to have RAII that things become complicated...
Just because a tool is in a box doesn't mean its useful. Considering the relative cleanliness, refactorability of code coming from the functional world (see Haskell and the like), it is debatable whether OOP is a "good" style to develop at all!
If I look at most of the libraries commonly used in production JS, pretty much none of them apply classic OOP principles.
> it is debatable whether OOP is a "good" style to develop at all!
You've drank way too much Kool-Aid here.
First of all: there are many different styles of OO, some more cumbersome than others, some so far removed from "classic OOP principles" that it takes effort to see how are they related. It's utterly useless to talk about "OOP style" as if it was a well defined, canonical set of rules - because it's not.
Second: there's nothing that makes OOP and FP be in opposition to each other. You should be aware - and if you're not, you should feel ashamed - that closures, one of basic FP tools, were supported in Smalltalk 20 years before Haskell.
Third: just as with OOP, things coming from FP are not uniformly "better" in any sense. Just as with every other paradigm, FP languages frequently have features needed only because they are FP. It makes very little sense to adopt those. Many really interesting features meant for solving real problems (and not for solving problems with a paradigm) are steadily coming to non-FP languages anyway.
> If I look at most of the libraries commonly used in production JS, pretty much none of them apply classic OOP principles.
Once again: either you have no idea what OOP is or you have no idea how JS libraries look like. For every http://ramdajs.com/docs/ you get hundreds libraries which implement their own kind of OO, starting from jQuery and Backbone.
To be clear, "closures" are merely an implementation of lamdbas which were invented in the 30s. I wouldn't mention it except you're trying to shame someone for not "knowing" that Smalltalk beat Haskell to the punch despite both of them borrowing from a much richer history.
To drive the point home, you can implement lamdbas (and thus Haskell) without using closures. In fact, this is easy in a pure language since bindings are static. One way to do this is to compile the language into a basis of combinators like SKI. These no longer have any notion of binding so we don't need closures. Likewise, you could compile it into a categorical semantics and maybe implement this on FPGAs—again, no need for closures.
Lamdbas are merely a syntax and theory. Closures are merely one interpretation given a Von Neumann machine.
I happen to know all this; what I wanted to stress is not the nature of closures, which is exactly as you say, but that they were used since long ago in a "purely object oriented" languages, which - AFAIK - are not meant to implement lambda calculus in any shape or form.
GP wrote that - in short "everything in OOP is bad, let's use FP only". I responded with an argument that, in fact, certain OOP languages used FP features long before Haskell (because that's the example GP provided). I don't think the fact that closures are just one interpretation of an abstract concept of "lambda" is very relevant to this argument.
And about "shaming" people: I meant to gently point out that advocates for some cause should at the very least get their facts straight. Bashing some concept without knowing it well is the thing I objected to, a "not knowing it well" part by itself wouldn't be anything one should feel ashamed of.
I suppose I read it overly antagonistically then. Honestly, the entire FP/OO thing is so draining. I wish we'd all just start talking about Church/Curry debates instead. It's dispense with most of the marketing mumbo jumbo.
Just because it's possible to write a program without a tool, doesn't mean it's more productive. Functional programming doesn't even directly oppose OOP, it opposes imperative. It is absolute basics of CS that there is data and logic and many problems are easy to reason about as logic modifying data (state). OOP is a tool that allows to encapsulate some data and logic that go together. Functional programming doesn't allow you much more than that. Just because you may (or may not) end up decomposing a program into the smallest units of logic, doesn't mean you've done something useful, or clean.
* FP as I understand it doesn't much oppose imperative or even most of OO. It opposes non-composability using discipline from pure/total languages.
* Even if you want to encapsulate data and logic together like you suggest, you only need to buy 10% of OO to get that (ADTs, existential types, modules, what-have-you do it fine if not far better). The remaining 90% may be a waste or actively harmful.
* FP, as I practice it, means using the simplest possible thing in a world where simple things compose nicely. This may end up being some kind of full-scale OO, I'm eager to try to find places where it does, but so far it hasn't ever.
As a meta note, "my kind of FP" is the Haskell type of purity and other such nonsense.
>FP as I understand it doesn't much oppose imperative or even most of OO
I think this is definitely true, if you take 'oppose' as 'incompatible'. If we look the design concept and plot them, there will be axes, and I think this is what we'll see.
>* Even if you want to encapsulate data and logic together like you suggest, you only need to buy 10% of OO to get that
That's also true, but it's not an argument against the seed of usefulness of the 10%. We have kitchen sinks because people pick and choose features at will.
>* FP, as I practice it, means using the simplest possible thing in a world where simple things compose nicely.
Same here, and everyone should practice this when they look at any function, or object method, trying to make it as atomic as possible.
> This may end up being some kind of full-scale OO
I don't think it's any more useful shoehorning a program into "everything objects" more than "everything is functions".
My point was to say that the core goal of OOP is a great one, it simply codifies something that people have done in C when they put structs and procedures in the same header file. Let's not throw the baby out with the bath water.
My point is merely that the benefits of are gained using essentially nothing more than real ADTs and yet are almost always bundled with harmful other things in practice. FP can include these core ideas nicely, much like how monads include imperative ideas nicely, by focusing on what composes well.
As long as I'm not using C++ I don't feel harmed by any OOP features I don't have to use. I don't feel being restricted. I'm curious, what are these commonly harmful things you're talking about?
On the other hand, most FP languages I tried feel very restrictive. The only language that is inclusive of all good ideas, seems to be F#.
I'm not a big fan of languages allowing mutability anywhere. You can use it, sure, but advertise in big bold letters as to where. This plays out repeatedly for any side effect.
There are some OO systems with effect types I suppose. Those would be interesting.
There are also OO systems that don't have mutability. But I think that it you remove mutation, all that class nonsense, and are careful with subtyping (since it breaks things badly often) then you basically have (badly typed) ML modules with open recursion.
The open recursion (a.k.a. late binding) bit is probably the most interesting thing but you can play with it in Typed LC just fine. It's just another form of recursion.
> Functional programming doesn't even directly oppose OOP, it opposes imperative.
Just to be pedantic, OOP is (a kind of) imperative programming: goals are achieved by performing a sequence of actions in the world. In functional programming, goals are achieved by defining values; the evaluation order is an implementation detail.
It could be argued that OOP is "more imperative" than, for example, procedural programming, since in an OOP approach, "the outside world" includes everything other than the current object (due to dynamic dispatch).