4 ms·
"Non virtual methods has nothing to do with OOP, they are a mere sugar for function calling." By this logic virtual functions are mere sugar for tables of func
by protomolecule 7y ago
"Non virtual methods has nothing to do with OOP, they are a mere sugar for function calling."
By this logic virtual functions are mere sugar for tables of functions and as such have nothing to do with anything besides functions and tables.
"We are talking about OOP, which is defined by late binding/open recursion"
Oh, well, definition of OOP is a moving target, everyone defines it as they like, but when we are talking
about trillion dollar mistakes, OOP certainly implies C++, Java, C# and such simply because Smalltalk and CLOS have been used on the far smaller scale.
Having established this, I'm sure you would agree that saying that OOP prohibits or discourages non-virtual functions is unreasonable. It does introduce virtual functions, but like every tool, they shouldn't be abused.
"a real world example"
Looks like a poor approach to concurrency or an example of abuse of virtual functions, or both.
"How do I know"
Well, a method you are going to re-implement needs to have a clearly defined contract. If it doesn't, it is either not supposed to be reimplemented or the codebase is of poor quality.
You can look at the set of virtual functions of a class as an interface. In the case of a plain interface you wouldn't ask 'how do I know how this interface is used?' - you don't and you can't, you just implement the contract. The same with re-implementation of virtual functions.
"In your example you explicitly redefining factorial"
No, I'm defining a new enhanced math function that reuses some existing code without understanding of its contract. Just like you do in your example :)
- ernst_klim 7y ago> Oh, well, definition of OOP is a moving target No, open recursion is the only thing that makes OOP a distinct paradigm. Without `self` you don't have OOP. [1] > No, I'm defining a new enhanced math function Yeah, no, you are redefining factorial in terms of different `pred` functions, and I'm simply defining `prev` without redefining factorial. [1] https://journal.stuffwithstuff.com/2013/08/26/what-is-open-recursion/ https://journal.stuffwithstuff.com/2013/08/26/what-is-open-r...
- protomolecule 7y ago"No, open recursion is the only thing that makes OOP a distinct paradigm. Without `self` you don't have OOP." I'm not arguing that open recursion is part of OOP definition, I just disagree that C++ and C# aren't OOP since they have it as an opt-in feature. You yourself happened to mention encapsulation as part of OOP in your original comment. While you can call bundling data and functions together a sugar, limiting the scope of data to class' methods is essential. Consider implementation of a hash map. Isn't it nice that the state is accessible only to {contains, get, set}? After auditing these three functions you can be sure that the invariant is never violated. How would you ensure that in FP? Thanks for the link, I myself happened to explain the complexity of virtual function contracts in the same way, nice to have it written down in case I need it again.
- andrenth 7y ago> Consider implementation of a hash map. Isn't it nice that the state is accessible only to {contains, get, set}? After auditing these three functions you can be sure that the invariant is never violated. How would you ensure that in FP? You can have the same with an abstract data type and a set of functions that operate on it. Only functions defined in the same module as the ADT can access its internals, so inspecting those functions would yield the same assurance you’d have in the OOP version. Arguably the FP version would be easier to inspect, because all data would be local (passed as a parameter), while the OOP version could have “semi-globals” in the form of instance variables.
- protomolecule 7y agoBut what I described IS an abstract data type and the concept of abstract data types appeared in CLU which is an OO language. What's more, encapsulation (data-hiding) don't seem to be an integral part of FP and Haskell's modules seem more like an exception than a rule. For example, listen [0] to the author of Clojure: "Fogus: Following that idea—some people are surprised by the fact that Clojure does not engage in data-hiding encapsulation on its types. Why did you decide to forgo data-hiding? Hickey: Let's be clear that Clojure strongly emphasizes programming to abstractions. At some point though, someone is going to need to have access to the data. And if you have a notion of "private", you need corresponding notions of privilege and trust. And that adds a whole ton of complexity and little value, creates rigidity in a system, and often forces things to live in places they shouldn't. This is in addition to the other losing that occurs when simple information is put into classes. To the extent the data is immutable, there is little harm that can come of providing access, other than that someone could come to depend upon something that might change. Well, okay, people do that all the time in real life, and when things change, they adapt. And if they are rational, they know when they make a decision based upon something that can change that they might in the future need to adapt. So, it's a risk management decision, one I think programmers should be free to make." [0] https://gist.github.com/rduplain/c474a80d173e6ae78980b91bc92f43d1 https://gist.github.com/rduplain/c474a80d173e6ae78980b91bc92...
- 7y ago
- protomolecule 7y ago"Yeah, no, you are redefining factorial in terms of different `pred` functions, and I'm simply defining `prev` without redefining factorial." No, you are not simply defining `prev`, you are creating a new class using `computer` as a base and supplying all its methods with the new definition of `prev`. Let me complete your example: class computer = object(self) method factorial x = if x = 0 then 1 else x * self#factorial (self#pred x) method pred x = x - 1 end class computer_enhanced = object inherit computer method pred x = x end obj_computer = new computer obj_computer.factorial(5) //still works obj_computer_enhanced = new computer_enhanced obj_computer_enhanced.factorial(5) //stack overflow And the same with my example: let rec fact(x, prev) = if x <= 1 then 1 else x * fact(prev(x), prev);; let factorial(x) = fact(x, fun x -> x-1);; let enhanced_factorial(x) = fact(x, fun x -> x);; factorial(5);; (*works*) enhanced_factorial(5);; (*stack overflow*) In both cases the old `factorial` works and the enhanced one fails.
- ernst_klim 7y ago> In both cases the old `factorial` works and the enhanced one fails. Does class computer_enhanced = object inherit computer method prev x = x end tells you that factorial definition changed and that it's dependent on prev? No. Does fact(x, fun x -> x) tells you that this function's behavior depends on `fun x -> x`? Yes.
- protomolecule 7y ago`factorial` definition hasn't changed, what changed is its implicit parameter. The word 'inherit' tells you that all methods of the `computer` class are potentially affected, including `factorial` unless you can see in `pred`'s contract that it affects only `factorial`. If you call your class `computer` and put a bunch of unrelated methods in it, then, yes, you are in big trouble, but you can abuse anything - you can create a data structure with hundreds of data members and make all your 'pure' functions take and return it. To sum it up: I see your point, but I don't think that it's a fatal flow of OOP, it's just a way to abuse it.