5 ms·
Number 14 is funny: it's like "do classes, but don't do what classes actually do". The first paragraph then goes about setters and getters that are specifics of
by de_watcher 8y ago
Number 14 is funny: it's like "do classes, but don't do what classes actually do". The first paragraph then goes about setters and getters that are specifics of some particular styles in some particular languages (and why you even need setters if you want to be clear about "not manipulating the data"?).
- bunderbunder 8y ago#14 fits into a fairly well-established trend of thought on object-oriented programming. A lot of us have noticed, over the 20-ish years since OOP really got popular, that doing it in the way most of us were taught in CS 101 (or wherever) tends to produce code that is difficult to maintain over time. In the particular case of mixing data storage and data manipulation in a single class: It tends to yield classes that continuously accumulate new functionality over time. They also tend to be difficult to refactor int a set of smaller classes. The level of impact on consuming code is very high, because splitting those classes tends to also force major changes to anything that interacts closely with them. And, since all that functionality lived inside a single class, it's likely to be internally resistant to change, too. It's really easy to treat "encapsulation" as a reason to not worry overmuch about shared use of glo^H^H^H instance variables. Does this kind of stuff mean that OOP didn't turn out to be all it was cracked up to be? Yup. Does this mean we're throwing the whole idea out? Nah, it's just evolving. The original idea's been augmented with other useful ideas like the interface segregation principle, the Liskov substitution principle (mixing behavior with data makes obeying LSP very difficult), and acknowledging the value of referential transparency.
- gagege 8y agoWhat I always ask is, why use classes at all? I love that newer language docs like the ones for Kotlin and Swift are telling people to use structs and bare functions.
- bunderbunder 8y agoTo name one example: Because it still allows you to write to a higher level of abstraction. So you can have all sorts of different data storage classes - lists, sets, hash maps, etc. - and decide that they all implement an "enumerable" interface, and then any functions that just need to be able to apply some operation to every element in a collection can work with every single one of your collection types. Haskell has ways of getting us that sort of thing with only structs and bare functions - and does a really nice job of it, too - but most of us aren't working in Haskell.
- kccqzy 8y agoYou are mixing different concerns. The Haskell example you are talking about is just interfaces, not classes. As for data abstraction, we can use modules; either the weak Haskell ones or better ML ones. Classes simply conflate the two concepts. I'd rather remove the feature of classes and introduce those two instead.
- croo 8y agoTo add another perspective to the discussion, Yegor Bugayenko (author of the Elegant Objects books) says that splitting data and data manipulating objects are "pure evil" because when you do it that way it is going against OOP as you will get functions and data to operate on. Which is exactly where we were before OOP. If you can get over of him calling everything "pure evil", the simplicity he tries to achieve with his controversial view on what is true OOP is quite interesting. I think that instead of this splitting to data and functions a better solution is to use Single Responsibility, Tell don't Ask, and Demeter's law. This way one can make classes small enough so functionality accumulation won't be a problem and a class will tell what to do only to their "neighbouring" classes. This way every change in the code will be somewhat local. Of course this is an idealistic view which fades with every ORM entity read... :)
- bunderbunder 8y agoI haven't read his book, so I can't speak to his arguments, but I did want to say that I don't think that doing so puts us exactly where we were before OOP. Classes can still be parameterized in a way that modules in procedural languages can't, which opens up all sorts of flexibility that wasn't available, or at least was exceedingly awkward to accomplish, in non-OO procedural languages. For example, you're going to want some sort of post-procedural language if you want to use dependency inversion.