6 ms·
> I'd say traits in Rust, typeclasses in Haskell and Scala imlicit views are the equivalent to Clojure/Script protocols. And similarly, those constructs by them
by likeclockwork 8y ago
> I'd say traits in Rust, typeclasses in Haskell and Scala imlicit views are the equivalent to Clojure/Script protocols. And similarly, those constructs by themself aren't OOP. I think a simple proof is that if they were, then all OOP languages would have them. But because there are OOP languages (the most popular ones at that) which don't have them, then it follows this construct is not fundamental to OOP.
This seems completely circular to me. Your definition of OOP is really "whatever all OOP languages do"?
> I'm not sure I'm explaining myself very well. Think of an object. The object defines some data fields. And it defines some methods together. You can't use those methods with other objects. The ownership is tied to the object that defined them.
In Clojure you can't use a protocol method on a type that doesn't implement that protocol. I don't see it as being that different from D's Uniform Function Call Syntax (a free function can be called as a method of its first argument and vice versa.)
What is OO to you? Is it Class Oriented Programming? Is it a programming paradigm or is it the list of features and practices common to a family of languages? Almost no common OO languages treat method calls as messages. It's just a function call with a (usually) hidden 'this' parameter. Applying a protocol function to a record that implements it isn't really any different, from a perspective of message passing. A message is passed to the record and based on its pedigree it decides how to respond.
Plenty of OO languages don't have private data and allow direct access to object fields. Arguably, by your definition, it isn't OO at all to even provide for public fields. As long as the methods follow the data around or vice versa, in my view, encapsulation has been achieved. Enforcement is another concern, but it's not Jail Oriented Programming so I don't see that enforced encapsulation is a necessary condition for OO.
A record implementing a protocol can receive method calls. All of its method implementations happen with the records own fields in scope (assuming you define them in the defrecord). It doesn't need to restrict access, if you'd like it to have private data.. respect its privacy and don't look.
As I understand it, the state of the art in Class-Oriented Programming has been to define interfaces for everything, and then define classes that implement those interfaces, and then use the interface to type functions and methods. A Trait in Rust or a Protocol in Clojure just knocks out the middle man, the unnecessary and unwanted class. What's left is still OO, you can get rid of the class and all of it's baggage and still have plenty of OO left.
> A record is a set of key/value pairs with an associated type. A Person record defines a type Person, with keys Age and Weight and their values. That's all a record does. It can't restrict access to its data, it can't expose methods, and it can't receive messages (method calls). You can now write functions that take input of this new type. Those functions can be defined anywhere. They have no special access to the data inside Person, there's no `this` or `self`. The functions don't live inside the datatype. Now, if you want a common set of functions to work over many different types, you can specify a protocol. That's all a protocol does. This is just functional programming.
This, to me, is a description of object-oriented programming without the class ceremony. It's also functional programming. The use of records and protocols is functional programming, but the constructs themselves have OO nature. I don't think functional programming and object oriented programming are in opposition to each other. I think functional programming and mutable state heavy/class-happy programming don't mix but the latter is not my definition of OO.
- didibus 8y ago> This seems completely circular to me. Your definition of OOP is really "whatever all OOP languages do"? It seems logical to me that for two things to be grouped together in the same category, some commonality between the things are required. So there has to be something in common with all OOP languages which makes them OOP. Otherwise, it is not possible for them all to be OOP languages. You're saying a language supports OOP if it has a protocol like construct. Sure, you can decide to define OOP as such. But then languages commonly refered to as supporting OOP, like Java, get excluded. So it seems to me it's a bad way to define OOP if it excludes Java, which is probably the most cited language when talking about OOP. > What is OO to you? It's a paradigm. Where your program models the problem using a concept known as an object. Characterised by the grouping of data fields and procedures responsible for accessing and modifying said fields. Objects know about both their fields and their methods. Where other code can only access the object's fields and the object's methods through a reference to the object itself. A pure OO language would have everything modeled this way exclusively. Thus nothing would exist outside an object, and you'd only have objects interacting with other objects. An impure OO language, thus a multi-paradigm language with support for OO, would allow part of your code and data to be modeled this way through objects, and other parts using other paradigms. Without resorting to interop, Clojure/Script, to my knowledge, does not have an object construct which fits this definition. > from a perspective of message passing. A message is passed to the record and based on its pedigree it decides how to respond The call isn't made to the record, but to the protocol function. A function is called, and this function decides what to do based on the type of the first argument. > Plenty of OO languages don't have private data and allow direct access to object fields. Arguably, by your definition, it isn't OO at all to even provide for public fields Those are impure OO languages, they are multi-paradigm. If you were to make all your data inside objects public, and never put any methods on the objects. And you would put all your methods outside of objects, or inside objects with no data and have them take objects with data as their first argument, then your program is no longer using the OO paradigm, it is no longer object oriented. > As long as the methods follow the data around or vice versa, in my view, encapsulation has been achieved Clojure/Script records don't have their methods following them around. You can define the functions for the protocol in another namespace, and then you have to require them separately. They don't tag along with the record. > A record implementing a protocol can receive method calls. All of its method implementations happen with the records own fields in scope (assuming you define them in the defrecord) Again, the call is made to the protocol functions. Simply importing the record does not make these functions exist within your namespace, you need to require them. And these functions are not scoped within the record. They don't see the fields, they need to access them through the record, like any other function would. Nothing is special about these functions. They're just functions that know how to do something to a concrete datatype. > As I understand it, the state of the art in Class-Oriented Programming has been to define interfaces for everything, and then define classes that implement those interfaces, and then use the interface to type functions and methods. A Trait in Rust or a Protocol in Clojure just knocks out the middle man, the unnecessary and unwanted class. What's left is still OO, you can get rid of the class and all of it's baggage and still have plenty of OO left No, what you're seeing is the evolution of languages away from OO. It is a direct result of the criticism applied to the OO paradigm, and traditionally OO languages recognising its shortcomings, thus evolving other paradigms or practices which bypass the OO model. All these languages are multi-paradigm in essence now. A trait effectively is an alternate concept from an object. It defines functions interface and implementation separately from the datatype. You can have a language with traits yet without objects, such as Clojure/Script. Such a language is not OOP. You can't take away the concept of objects and still be object oriented. This is just support for type polymorphism, and it's ortgogonal to objects. I think you might be the one with a circular definition of OO. Because you see things in languages that have support for OOP, does not mean all their features are part of the OOP paradigm. Take Java, remove its support for interfaces, now ask yourself if it still supports object oriented programming? Yes? Why? At least, this is my taxonomy. But I feel it is also the most common taxonomy in use. And I also feel it is a more useful taxonomy. Things are more granular, more specific. And within this taxonomy, the criticism against OOP is well founded, and more convincing. And it makes sense then that Rust and Haskell and Clojure/Script do not advertise support for OOP. It makes sense why Java, which lacks Traits, is still OOP, etc. Just my 2 cents.