4 ms·
> So how would you define OO? I get it your are in the camp that equal polymorphism to OO? And by the way, I do see it. Clojure/Script has object-based construc
by likeclockwork 8y ago
> So how would you define OO? I get it your are in the camp that equal polymorphism to OO? And by the way, I do see it. Clojure/Script has object-based constructs. If you think of the more general sense for object, which is identity + attributes, records fit the bill. This is defined here https://en.wikipedia.org/wiki/Object_(computer_science)#Obje... https://en.wikipedia.org/wiki/Object_(computer_science)#Obje.... Now, I also agree with you, it even has a construct that groups data and behavior together in the form of deftype with mutable fields. So at this point, it has support for OOP.
> 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.
- didibus 8y agoI don't think I'm able to understand what you consider OO to be then. It really seems like you make it out to be type polymorphism. For example, is this OO (in pseudo-code): person = [:person "John" 23]; animal = [:cat "Moonshine" 5]; function talk(object) { switch(object[0]) case :person return "I'm " + object[1]; case :cat return "Miow " + object[1]; } talk(person); talk(animal); In your eyes?
- likeclockwork 8y agoNo, that's just a switch statement. OO is the inverse of that. The objects need to bring their own code with them in some form or another. So a vtable, a struct/map of functions, a closure around a struct/map of functions, a closure of state, and that sort of thing would be your minimum OO with no real language support.
- didibus 8y ago> The objects need to bring their own code with them in some form or another. Can you clarify what counts as "with them"? For example, does this count #1: person = [:person "John" 23]; animal = [:cat "Moonshine" 5]; talk-protocol = {:person (object -> "I'm " + object[1];) :cat (object -> "Miow " + object[1];) function talk(object) { call(talk-protocol.get(object[0])); } talk(person); talk(animal); Or is it more like this #2: person = [:person {:talk (object -> "I'm " + object[2];)} "John" 23]; animal = [:cat {:talk (object -> "Miow " + object[2];)} "Moonshine" 5]; call(person[1].get(:talk)); call(animal[1].get(:talk)); Or would you consider both an instance of "bringing their own code with them"?
- likeclockwork 8y agoI'm not sure I really understand the point of this exercise but I'll play along. I'm not going to write in that EDN + CoffeeScript pseudocode. I don't really like those kind of types without pattern matching. I do wish JS had keywords though. Lets use modern JS and pretend that JS objects are simply heterogenous maps of String -> any... let cat = { talk: () => "Meow" }; let person = { thinkingAbout: "Politics", talk: (self) => `Have you heard about ${self.thinkingAbout}?`, thinkAbout: (self, topic) => self.thinkingAbout = topic }; function invoke(object, method, ...args) { return object[method](object, ...args); }; invoke(cat, 'talk'); invoke(person, 'talk'); invoke(person, 'thinkAbout', 'TV'); invoke(person, 'talk'); That'd be one example of a very bootleg object system. If you want examples on how to build an object system so you can do OOP in a language that doesn't intentionally support OO... look into the Common Lisp Object System, or for some object-oriented C code (there's a lot of it out there), or see Chapter 3 of SICP: https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book-Z-H-20.html#%_sec_3.1.1 https://mitpress.mit.edu/sites/default/files/sicp/full-text/... Both of your new examples are more OO than your last one. CLOS is basically something like what we've been doing + way more effort than either of us is going to put into this. Your switch statement example was such a straw man it's hard to even say what was wrong with it. Polymorphism in OOP replaces switching on type every time you define a method. This isn't a rule, but I think OOP should be on the opposite side of solutions to the expression problem from switch statements and pattern matching. Again: In the mind of the average dev any construct that doesn't exactly mirror the semantics of classes isn't OOP. There are people who didn't consider JS to be OO because it didn't have classes. (It still doesn't, but it pretends to so they say "now its OO".) I really can't stress this enough. The languages we were talking about before aren't extreme straw man examples of OOP, like these snippets are. EDIT: I should add with regard to these examples that I don't think it's necessary that data and behavior be grouped in definition as long as they can be treated so at the site of invocation even if the methods are invoked in the same manner as free functions.