> I know some people say polymorphism alone is the essence of OO. Thus Haskell, Rust, Clojure/Scipt, Go, PureScript, and others are all OO languages. I don't know though, I feel the average dev doesn't think of it that way.
I don't think that polymorphism alone is sufficient to be considered OO. I think it's important to recognize you can do OOP without much language support, people even do OOP in C. There's probably someone doing OOP in assembly somewhere.
> But, after this conversation, I wonder if I don't prefer the definition from the wiki link I shared. Where OOP is the combination of all three. A single construct which groups data and behavior, and allows polymorphism as well as inheritance. And this is what is known as an object, and all three must be present to be considered OOP. With this definition, I think Clojure/Script wouldn't fit as OOP. Since, and tell me otherwise, deftype doesn't support inheritance. And multi-methods don't group data and behavior.
Lets work with your definition..
You concede that all of those constructs group data and behavior, since they let you define a type's methods in a manner that has access to that type's internal implementation. You concede that they allow polymorphism because you can substitute any type that implements the trait/protocol/interface/typeclass. I don't think subclass inheritance is necessary to OO because it's there as a means of expressing type polymorphism and in the class-bases languages it was for the longest time the only way of expressing type polymorphism. So.. what's the difference between participating in an interface/trait/protocol and inheriting from an abstract class? I don't particularly think there is any (some of these languages even have default implementations, including Haskell), you get subtype polymorphism from either.. so in my view the inheritance requirement is met even without a full-blown class hierarchy or deep prototype chain.
> Those methods are no longer trait like, they're full blown object methods, with special privileges, and tight coupling to the mutable data fields. They can not be defined separately to the type, and a type can not be extended outside its definition to support such methods.
All of the other constructs work the same way, even typeclasses in Haskell. Trait implementations in Rust can have privileged access to private fields. I assume it's the same with Go interfaces. And in Haskell you can't destructure or even construct a type if you don't have access to its constructor--so if you don't export the constructor from your module.. all your fields are private. But you can export a function that constructs the type. You can export the typeclasses. You can export accessors for public fields, and functions to return a modified version of the instance and so forth.
> I know some people say polymorphism alone is the essence of OO. Thus Haskell, Rust, Clojure/Script, Go, PureScript, and others are all OO languages. I don't know though, I feel the average dev doesn't think of it that way.
Well, they're not all OO languages. They all do have language level support for all of the concepts that OOP is made of and you can use them to do Object-Oriented Programming even though some of them are clearly Functional Programming languages. OOP means classes and nothing else in the mind of the average dev. In my opinion it's really just a pattern that you can apply/implement anywhere with more or less support from the language and in sufficiently flexible languages you can even build your own object system and it might even be nice to use. Supporting OOP doesn't make a Functional language not-Functional, or even a multi-paradigm language. No one would call Haskell a multi-paradigm language, yet it has language level support for OOP. Classes and FP don't really mix, but OO in FP works and doesn't have to compromise the FP paradigm. OO isn't something you need to dedicate an entire language to in order to use or benefit from.