Tying methods to data is an inevitability (whether it is on run- or compile- time). Can you give me an example of a function that does not depend on the data it operates on?
What makes OOP wrong is not tying methods to data, but tying data to ontologies. Limiting a function to operating on what something "is" is an artificial limitation. Limiting a function to operating on what something "has" or "can do" is a logical consequence.
>Tying methods to data is an inevitability (whether it is on run- or compile- time). Can you give me an example of a function that does not depend on the data it operates on?
I mean tying methods to data via a class. A instantiated class is a structure that has data and has methods specific to operating on said data. Either way, any function that takes void input and with any return type is an example of a function that does not depend on data, but that wasn't my point.
Note that a function is different from a method contextually speaking.
>What makes OOP wrong is not tying methods to data, but tying data to ontologies. Limiting a function to operating on what something "is" is an artificial limitation. Limiting a function to operating on what something "has" or "can do" is a logical consequence.
We may be talking about the same thing. Though I'm not sure what you mean by this: "Limiting a function to operating on what something "is" is an artificial limitation. Limiting a function to operating on what something "has" or "can do" is a logical consequence." Can you please clarify?
We might want to agree on what we mean with "OOP", since it's such an abstract term we might be talking about different things.
> Note that a function is different from a method contextually speaking.
I disagree. A method is just a function with an implicit self/this parameter. I see methods as just namespaced functions with syntactic sugar to call them with dot notation from instances.
In Rust this is particularly prominent, since they support UFCS:
whatever_instance.method(arg1, arg2)
...and...
Whatever::method(whatever_instance, arg1, arg2)
...do the exact same thing. Other languages are more limited in their syntax, but I don't think it's inherent to OOP.
I think I see what you mean with "contextually speaking" but I can't really see the difference neither in theory nor in practice.
> Can you please clarify?
I'll try :P Maybe with an example.
In TypeScript we can define types as "interfaces" (do not confuse with what Java calls "interface").
interface Named {
name: String
}
Then you can make a function that takes Named things:
function sayHello(named: Named) {
alert(`Hello! My name is ${named.name}.`)
}
My point is all functions are tied to the data they work with, whether explicitly or implicitly (via runtime errors).
This is what I mean with "has" or "can do". I couldn't care less whether that Named was instantiated as a Dog or a Person class, as long as it has a name. (Just to clarify, I don't think TS's interfaces are particularly good either, since they're tied to the actual object shape, what if my object has a field "fullName" instead?)
I agree with you if we only consider traditional OOP class-based abstraction. Modern forms of OOP on the other hand are a blessing for me.
- Classes should be limited to creating particular object instances that group together a bunch of interfaces.
- Class methods should only be used to manipulate that particular instance, with its particular idiosyncrasies, never as a means of abstraction. Only the class itself should know about its methods.
- Classes expose functionality via interfaces (that internally use the class methods).
- Therefore no function should declare an argument by class ("is"), only by interface(s)/trait(s)/whatever(s) ("has"/"can do").
Why use classes then? Mostly for the namespacing and the syntax sugar. The name "class" is probably not very fitting but it's probably hard to get rid of.
So, in essence: I think we agree on the problem but disagree on the culprit. It's not OOP. It's C++/Java/C#/etc.
> Either way, any function that takes void input and with any return type is an example of a function that does not depend on data, but that wasn't my point.
I was sure you were going to say this :P We can agree it's hard to write an useful program with constant pure functions.
Just for fun: I'd argue it still depends on the data it operates on... in this case, the empty set!
>Just for fun: I'd argue it still depends on the data it operates on... in this case, the empty set!
Void is not an empty set. It is void. Nothing. I am referencing the category void here. I'm not too familiar with rust but in rust this is just an empty enum.
Note that functions with parameter void can never be called because the void type can never be instantiated. You cannot instantiate nothing. This is a very theoretical concept, but I believe in rust you can actually define (not call) a function of this type.
fn absurd<T>(x: SomeEmptyEnumType) -> Int { 1 }
It's def hard to write a useful program made up of functions that can't even be called.
>So, in essence: I think we agree on the problem but disagree on the culprit. It's not OOP. It's C++/Java/C#/etc.
Took me a bit to parse what you're saying. I get it and you're right. What is the problem with C++/Java/C#/etc?
Notice I said "is-a" polymorphism (I should've said inheritance to avoid confusion: class Person; class Employee is-a Person; class Client is-a Person; etc.). I mean an ontology of classes.
> What makes OOP wrong is not tying methods to data, but tying data to ontologies. Limiting a function to operating on what something "is" is an artificial limitation. Limiting a function to operating on what something "has" or "can do" is a logical consequence.
But the “is”es in proper OOA&D, and hence OOP (at least the ones you should be coding to), are of the form “is a thing that can do”.
If you mean: never declare a function as taking a particular class instance ("is"), only interfaces/traits/mixins/whatever ("has" / "can do").
Then yes, we agree.
As soon as you declare a function as taking a class instance, you're limiting to what something "is". I don't think ontologies are particularly useful as a means of abstraction.
Yes, you can do better with careful architecture, but the footgun is still there and I'm just saying we should probably get rid of it instead of working around it.
Tying methods to data is an inevitability (whether it is on run- or compile- time). Can you give me an example of a function that does not depend on the data it operates on?
What makes OOP wrong is not tying methods to data, but tying data to ontologies. Limiting a function to operating on what something "is" is an artificial limitation. Limiting a function to operating on what something "has" or "can do" is a logical consequence.