struct Cat {
meow: String
}
impl Cat {
fn talk(self) {
println!(self.meow);
}
}
fn main() {
let bob = Cat { meow: "Mroowwwww!" };
bob.talk(); // Prints "Mroowwwww!" Good job, bob.
}
Cat lumps the data and its associated functionality together into an object. This is object-oriented programming even if you never bring inheritance into the picture.
Both Go and Rust have objects, they simply go by the name struct. Haskell does not follow the object-oriented approach.
I think the confusion surrounding OOP is that people associate OOP with a particular implementation of it, like Java.
Sure, but with that wide a definition its really hard for a programming language not to be object oriented. C can be just as object oriented with structs, unless you consider bob.talk() to be just completely conceptually different from talk(bob) where talk's definition expects a Cat struct. Similarly, under your example, Haskell is also object oriented since you have data types with fields and functions that can only operate on that kind of data (Again at this point you'd really be arguing that the order of function/caller is the "OOP differentiator" since (ignoring inheritance), there is no difference between Cat's talk method and a talk function that takes in a Cat).
In other words, I don't think anyone is ever arguing against organization of data and functions into more abstract "types". Pascal does this with Records, C with structs, Haskell with data types, C++ with classes, JavaScript with prototypes, etc etc. So if thats all it takes to be "OOP" (in other words, not forcing you to only use ints and floats), then I guess I agree that OOP is a better representation of the world. But now I'd argue that the more interesting discussion is between the has-a and is-a versions of this.
You have to draw the line somewhere. The structure of a typical OOP language program such Go, Rust, Java, C++, C#, etc. are not comparable to that of a typical Haskell program.
All of the languages that are considered OO rely heavily on the binding of data and functions into objects.
Others will have deeper ideas of what an OO language needs to have, but the basic definition is about objects. That is, the binding of data and functions into an object.
In modern OOP discussion, it seems many already have come to the conclusion that inheritance is something to be used very sparingly, and can be done away with in favor of composition in most use cases.
I agree that you have to draw the line somewhere, but I believe the is-a/has-a dichotomy more accurately separates the different modes of thinking. To me the structure of a Go program is completely indistinguishable from one in C++ (precisely because of the lack of inheritance). When I look at the design of a C++ program (or say Obj-C), its all about class hierarchies. The docs are all about the class diagrams, step 1 of most those programs is usually "subclass ___". It immediately drops you into that view of the world, and I believe that with that view comes the guiding hand of your program's design.
Compare that to Go, which focuses on the traits of objects instead of their incidental ancestry. In go you'd define a function or method applying to an abstract interface that has certain properties. For example, I would say "give me an object that has a show method", not "give me something inheriting from Printable". This is completely analogous to the very abstract typeclass-style programming you do in Haskell ("give me something that derives Show"). Haskell object architecture is all about defining an abstract typeclass and reasoning about what you can do given these existing methods. You then supply an implementation that fits the type class definition, exactly the same abstract analysis of fundamental properties divorced from their specific owners as inheritance-less interface/protocol programming in a language like Go.
Again, there is quite literally no difference in "binding" a function to an object through the dot syntax vs through type. If in haskell you say the meow function applies to the Cat data type its not any different than having a meow() method on a Cat in C++, neither can call that on anything else, its quite bound.
Also, I agree with you about the point of C being used in an OO fashion. I think this goes to show that a language doesn't need to specifically support objects/methods to wield in an OO-manner, it is just more inconvenient.
Haskell lacks basic OO features but that in itself is a feature. Methods are often procedural in nature. They're also not generalized since they are a concrete implementation for a specific type. Both of these are completely contrary to Haskell style.
Rust's trait system is essentially identical to Haskell's typeclasses, and Haskell allows infix operators which work exactly like method calls, except that you don't have to put a period between the data and the function. So it seems to me that by your definition Haskell is also object oriented.
(As for my personal opinion: I think the confusion around OOP is largely a product of it not having a precise definition).
For example, if you have:
Cat lumps the data and its associated functionality together into an object. This is object-oriented programming even if you never bring inheritance into the picture.Both Go and Rust have objects, they simply go by the name struct. Haskell does not follow the object-oriented approach.
I think the confusion surrounding OOP is that people associate OOP with a particular implementation of it, like Java.