7 ms·
>The signature of the original sort function remains the same. But you have a general function that can be reused in different contexts. This type of change CAN
by kingdomcome50 7y ago
>The signature of the original sort function remains the same. But you have a general function that can be reused in different contexts. This type of change CANNOT be done on OOP.
This is where you lose me. The above is simply untrue. There is absolutely no reason one cannot employ `SortingAlogrithm.sort` within the body of `people.sort()`. Are you suggesting every utility class (and by extension the entire standard lib) needs to be injected into an object before it can be used?
Again, you are creating a false-equivalence. A "fair" example would require our generic `sort(comparable)` be passed into the original as a dependency like so: `sort(people, csort)`. It's _possible_ that the two functions could be composed, but that is completely dependent on the semantics of each function (we cannot just assume composition is possible for every use-case).
The difference between a first-class function and an object is purely semantics. Yes, you have to `new` an object before you can call a method, but there is no requirement any "implicit context" has to be provided at the time of instantiation. Closures offer the exact same capability via "capturing" and partial application.
Conceptually, all OOP does is take 10 functions that all have the same parameter and "partially apply" each of them over that parameter into new functions that don't have a parameter (i.e. they get that "implicit context"). That is, OOP saves you a step. It is common practice in FP to start with "pure" functions then, higher up in the application, partially apply those functions into new, domain-specific functions with your data (a.k.a. dependency injection) that are strung together to carryout a use case. OOP allows you to _define_ partially applied functions instead of the need to compose them (of course this also makes the DI mechanism a bit different as well).
I can agree that the above _can_ make decomposition more difficult, but your general critique reads more of one leveled at programmers not understanding the basic principals of software design, not OOP. I could just as easily create a mess in FP as in OOP.
>More importantly, is there a meaningful difference or is it just semantics?
I urge you to sit down and write out the pseudo-code. It will be plainly obvious that there is no meaningful difference between each approach.
- crimsonalucard 7y ago>This is where you lose me. The above is simply untrue. No. My statements are true. But you are right about you being completely lost. >There is absolutely no reason one cannot employ `SortingAlogrithm.sort` within the body of `people.sort()` Let's talk about objectives and what you're implying with this suggestion. The objective is to sort a bunch of people within the the people class. What is SortingAlogrithm.sort? Is it an object that sorts its own state or is it a stateless class with a stateless function? If it's an object that sorts its own state then it CAN'T do what I want. I want it to sort peoples' state NOT it's own state. If it's a stateless class with a stateless method then you are no longer doing OOP you have created a function that is not tied to state thereby proving my point that stateless functions are more modular. >Are you suggesting every utility class (and by extension the entire standard lib) needs to be injected into an object before it can be used? Yes this is the model in pure OOP languages. Otherwise you are using a hybrid of OOP and functions thereby providing evidence that OOP alone is broken. Things like JAVA, C++ do all kinds of BS like this further ingratiating my point. >Again, you are creating a false-equivalence. No. You are failing to understand. 'Lost' was the term you, yourself used. >A "fair" example would require our generic `sort(comparable)` be passed into the original as a dependency like so: `sort(people, csort)`. This is not fair at all. in fact it's ugly. I pass a generic sort as a parameter into a specific sort? If you think that's fair and you code this way then you're in for a surprise when building a complex system. >It's _possible_ that the two functions could be composed, but that is completely dependent on the semantics of each function (we cannot just assume composition is possible for every use-case). I'm thinking you got confused by what I mean by composition. There are two compositions I am referring to in my statements. Function Composition and Object Composition. Object Composition is exactly the previous example you gave sort(people, csort) or inserting something via the constructor People(csort), there's a number of ways to do it. Function composition of A(x) and B(x) is F(x) = A(B(x)). Function composition is at the heart of functional programming. >It's _possible_ that the two functions could be composed, but that is completely dependent on the semantics of each function (we cannot just assume composition is possible for every use-case). If you're not changing state and something has properties of being sortable it can be done. you have x = sortableListOfPeople composedFunctions = f(sortableListOfPeople) {return doPeopleSpecificStuff(sortGeneric(sortableListOfPeople))} you can go the other direction if you want. The implementation is situation specific but if something is sortable this can be done always but only if all functions are stateless and don't modify values. Note composedFunctions should have the exact function signature of the original function thereby negating the need to change other things dependent on it. >The difference between a first-class function and an object is purely semantics. No. A first-class function cannot change. It is immuteable and when called with the same input Always has the same output. An object with a method when called at different times can have different output based off of internal state. Your statement is categorically wrong. >Yes, you have to `new` an object before you can call a method, but there is no requirement any "implicit context" has to be provided at the time of instantiation. Then you are basically declaring a stateless function. The admission that you have to do this is an intrinsic flaw. Yes nothing prevents you from going outside of the OOP paradigm when programming in an OOP language. You likely have no choice due to inherit flaws in OOP. Try doing OOP without this ability... You'll see how broken the whole model is. >Conceptually, all OOP does is take 10 functions that all have the same parameter and "partially apply" each of them over that parameter into new functions that don't have a parameter (i.e. they get that "implicit context"). That is, OOP saves you a step. It is common practice in FP to start with "pure" functions then, higher up in the application, partially apply those functions into new, domain-specific functions with your data (a.k.a. dependency injection) that are strung together to carryout a use case. OOP allows you to _define_ partially applied functions instead of the need to compose them (of course this also makes the DI mechanism a bit different as well). Let me tell you definitively. I completely understand what you're talking about, I understand it now and I understood it before. No need to reiterate. What you're not understanding is that despite my 100% comprehension of your statements I am telling you, that you are failing to understand ME. Let me try to put it as simply as possible. If there is an Object called Number and a method called addOneAndReturn... if I call that method on a Zero Twice? what happens? I get One and then I get a two. The method is returning two different values despite being called in the same way TWICE. This sort of thing is NOT POSSIBLE in a stateless function. It Cannot Happen period. THIS is the fundamental difference. THIS is MORE than semantics. Yes I understand that currying and first class functions have parallels to Dependency Injection BUT there is still MORE then a semantic difference between OOP and functions. >your general critique reads more of one leveled at programmers not understanding the basic principals of software design Design is the domain of things we don't understand. There is no design in type theory or number theory because we understand all the implications of the axioms and theorems. We go to design when there is no formal theory that can say why one design is better than others. I am not coming from the design perspective. I am coming from the theory perspective. When you tie functions with state the state must move along with the function. If you keep state and functions separate then they can move separately. This is logic. No design principles needed. Any language with too many design patterns is a language that is very much lacking in a formal description (think: JAVA) >I could just as easily create a mess in FP as in OOP. You can. But there are more ways to do it in OOP then in FP. In fact there are more ways to shoot yourself in the foot in OOP than in procedural programming in general. I'm not even referring soley to FP. Even C is better than C++. >I urge you to sit down and write out the pseudo-code. It will be plainly obvious that there is no meaningful difference between each approach. You don't need to write psuedo code. Use your brain dude. A stateless function versus a function that carries it's own mute-able state. There is MORE than a semantic difference. The semantic difference you're referring to is when the SELF value is immuteable. In that case the two ways of calling the function become more similar, but THAT is NOT OOP. There is one rule that needs to be followed to make ANY program FP. Just one rule, that's it. Make all things immutable. OOP is fundamentally different from this because it involves the mutation of Object state.
- kingdomcome50 7y agoI fear the goalposts have moved from "the problem with OOP" to "the problem with mutability". These are distinct concepts. The fundamental premise of OOP is, among other things, the encapsulation of behavior _with_ data (as opposed to _around_ data). It has nothing to do with mutability. One can absolutely practice OOP with immutability (looking at Scala here). Similarly, OOP doesn't need to be written imperatively. Are you suggesting `sorted_people = people.sort()` isn't OOP? You are building your own concept of OOP to argue against, not the one that exists in reality. (straw-man emoji)
- crimsonalucard 7y ago>I fear the goalposts have moved from "the problem with OOP" to "the problem with mutability". These are distinct concepts. No they ARE not. For OOP to work you have to have objects be mute-able. The modern definition of OOP are nodes that communicate with each other and change each others state. The minute you get rid of mute-ability is the minute you are doing functional programming. >One can absolutely practice OOP with immutability (looking at Scala here). Scala is a multi-paradigm language. Also scala is not always immutable. The objects in scala can mutate. >Similarly, OOP doesn't need to be written imperatively. It does if you want the properties of an object to change. That is the dichotomy of OOP and FP otherwise there is no dichotomy and no point for there to exist vocabulary to separate the two concepts. >Are you suggesting `sorted_people = people.sort()` isn't OOP? If I remove the engine from my car and roll it down a hill while in the drivers seat am I still driving the car? Yes. Technically I am. But key feature of the engine moving the car is missing. You can call people.sort() OOP you can also call it not OOP because it is missing the key feature of self modification. >You are building your own concept of OOP to argue against, not the one that exists in reality. lol lets look at the definition. https://en.wikipedia.org/wiki/Object-oriented_programming https://en.wikipedia.org/wiki/Object-oriented_programming I directly quote from the site above: "Object-oriented programming (OOP) is a programming paradigm based on the concept of "objects", which can contain data, in the form of fields (often known as attributes or properties), and code, in the form of procedures (often known as methods). A feature of objects is an object's procedures that can access and often modify the data fields of the object with which they are associated (objects have a notion of "this" or "self"). In OOP, computer programs are designed by making them out of objects that interact with one another." Key sentence above: "A feature of objects is an object's procedures that can access and often modify the data fields of the object with which they are associated" The goal post was never moved. It was set by the Actual definition of OOP. I am explicitly including this feature to make sure that ALL we are dealing with is OOP and not some hybrid functional or OOP merger. >(straw-man emoji) This mechanism of turning macros into emojis doesn't work here on HN! Similar to your arguments.