5 ms·
While a lot of people make objects for the sake of making objects, I think it is instructive to think why you want to make objects in OO. As another poster has
by mikekchar 8y ago
While a lot of people make objects for the sake of making objects, I think it is instructive to think why you want to make objects in OO. As another poster has said, what if I had structs and functions with multiple dispatch? Why would that not be better than OO?
People tend to think of OO as a way of encapsulating data and then providing access to it. I rather think of it as a way of encoding program state. Often you have multiple operations that you want to perform on the same program state. It is nice to group that code together. Indeed, we have a computer sciency word for that: cohesion.
In FP, too, we do exactly the same thing. Take a look at any modern FP program and you will see that it is usually broken down into modules that represent program state. The modules contain code that operates on that state. We do it for the same reason we do it in OO: it creates good cohesion.
Getting back to my original question: why not structs with multiple dispatch? Actually, I wouldn't mind that at all (what's not to like about multiple dispatch?). However, the problem, I actually have is the struct. It's the same problem I have with the way many people approach OO: they are thinking about the code from the perspective of how to encapsulate data, not about what functionality they want. They are thinking about raw data instead of program state. A struct is a fine place to store data, but it's not the first place you want to go when you are doing design.
Instead you want to build your functionality and identify where you have commonalities in state. Then you should start thinking, "Hey these are using similar state. Are they related? Would it be more cohesive if I grouped them together?" Of course, it would be kind of strange to do that all the time. Most experienced programmers have a pretty good idea what program state they need to work on before they start. They can design data structures that are likely to be needed ahead of time. However, the priority should be to adjust the data structures to match the needs of the program state and to create more cohesive programs -- not to provide rigid boundaries separating your code.
Of course, nothing I've said is much different than programming in FP, and I wish that were not a surprise. OO and FP are not really so different. It's pretty easy to make the exact same mistakes in FP as you can make in OO. I sometimes feel like FP is just not popular enough to have widespread bad practices (like writing entire applications using only free monads).
- dnautics 8y ago> People tend to think of OO as a way of encapsulating data and then providing access to it. I rather think of it as a way of encoding program state. Often you have multiple operations that you want to perform on the same program state. It is nice to group that code together. That's very consistent with the original definition of OO, which hardly anyone uses much anymore. And erlang and elixir (and Ruby if you follow Gary Bernhardt) both fps do that quite well, via the actor model. Where OO starts to fail is when you gave to make a decision between two objects, e.g. "knight attacks mage" is the "attack" function a member of knight or a member of mage? Grouping functions by what state they touch is basically just namespacing, common between OO and FP.
- austincheney 8y agoIn the spirit of separation I would envision knight and mage (nouns) to be objects containing data properties defining their characteristics against an interface. The action (verb), attack, is a function which makes decisions and has portability. Expressed as separated semantic components knight attacks mage would be a subject, action, predicate relationship and each piece is individually portable and mutable.
- chriswarbo 8y agoI think you missed the real question: should the verb be `attack` or `defend` (i.e. "defend from", or "attacked by")? In class- or prototype-based OOP, we have to choose between `knight.attack(mage)`, with the functionality living inside `knight`; or `mage.defend(knight)` with the functionality living inside `mage`. > The action (verb), attack, is a function which makes decisions and has portability. OOP discourages standalone functions, so this function would either have to be in the knight, in the mage or (I would argue even worse) some sort of `GameState` object.
- austincheney 8y agoI guess it would depend upon the rules at play and various other unspoken variables, but generically speaking I don't see the difference between attack and defend in this limited scenario. One agent is interacting with another. The same instruction set would apply if it were knight attacking mage or mage attacking knight. > OOP discourages standalone functions Oh how I detest OOP. Portability of atomic components is amazing. So is scope nesting. Its like driving to work whenever you want in any of your cars (or your neighbors) instead of checking out a car from a car model inherited by a sedan class inherited from Toyota car class when such a thing becomes available.