4 ms·
>You are misunderstanding what I am asserting here. If the body of `sort(people)` is coupled to a property of `people` not present on `comparable`, you cannot _
by crimsonalucard 7y ago
>You are misunderstanding what I am asserting here. If the body of `sort(people)` is coupled to a property of `people` not present on `comparable`, you cannot _just_ refactor to a more generic `sort(comparable)` and expect the behavior to remain consistent.
Refactor sort into the composition of two functions. One is reliant on people, the other is just sort. 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.
>composition can be used instead of inheritance in tandem with double dispatch, for OOP, if the public surface of SortedGroupOfCats must include a `sort()` function
composition moves the entire state across. Think about it. I have SortedGroupOfCats and you want me in order to reuse sort, move SortedGroupOfPeople into SortedGroupOfCats.
>And while it makes for a great quote, Joe Armstrong is simply wrong. There is nothing inherent to OOP (and even less so when examining the languages that utilize the paradigm) that requires poor design.
OOP is bad because it makes it possible to shoot yourself in the foot, and while avoidable, unfortunately the syntax promotes designs that tend to be bad.
>More importantly, is there a meaningful difference or is it just semantics?
There is.. a function does not need to be instantiated to be used. A function never modified an entity. That changes everything. The fact that lambda calculus and turing machine exist in a theoretical sense shows you that the industry knows about an intrinsic difference between the two concepts.
>FWIW, I prefer a functional paradigm myself.
Note that although I have used the functional paradigm as an example this is not my overall critique. I am not just saying OOP is better than functional programming. I am saying OOP is worse than imperative, procedural and functional programming. Out of all of the most popular ways of programming... OOP is the least modular and the one with many many design issues. Even non-functional programmers have noticed this... GO is one of the results of this realization.
There are cases where OOP works, but in most cases, it's sub-optimal.
- crimsonalucard 7y agotypo up above: >I am not just saying OOP is better than functional programming I am not just saying functional is better than OOP
- 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.