8 ms·
I disagree with the article, which talks about building a holistic understanding when learning, and then ironically misses the forest for the trees regarding pr
by dymk 4y ago
I disagree with the article, which talks about building a holistic understanding when learning, and then ironically misses the forest for the trees regarding programming metaphors.
The author is obviously an experienced programmer, so I suspect they've forgotten what the mindset of an absolute novice is like, and to start programming with zero prior exposure to the concepts.
For the novice being introduced OOP, the `Duck / Cat / Dog <: Animal` analogy is useful to demonstrate how things like inheriting methods and sharing behavior works. It helps one start to think in terms of hierarchies and the boundaries between "concepts" in code. Obviously, in 'real' code, you won't be writing much that involves a literal hierarchy of animal species.
That's not the point. A beginner knows what a dog and a duck and a cat are in the real world. The "a-ha!" moment is mapping real-world relationships into a brand new abstract environment called Object Oriented Programming.
When you've never written a line of code in your life, abstract things like "network protocols" and "file I/O" and "ImageDisplay" (which is neither an image nor a display) are confusing, and so frustrating, and so not useful for teaching a complete novice.
- redisman 4y agoI disagree. Teaching people to think about abstractions wrong is not in any way helpful. Everyone I know including myself had to spend years writing bad code before realizing that this way of thinking is counterproductive. It reminds me of this quote from Kung Pow Don’t worry about Wimp Lo, he’s an idiot. We’ve purposefully taught him wrong… as a joke. Composition is an infinitely better method to teach if you have to teach OOP. That way you don’t need to unlearn what you thought was the right way but is actually useless at modeling almost anything.
- JoshCole 4y agoAbstractions are useful because they simplify and if you don't allow error you don't allow maximization of simplification. You can formally relate this to learning problem formulation complexity. When you do you encounter things like branching factors which effect solution times which lead to natural results like fast but finishes being better than optimal but never terminates. This can hold even despite error in the abstraction and there are techniques for recovering that error at runtime because a particular problem is a less general and more specific situation and so isn't as cursed by branching factor. Edit: A previous version of this comment was more wordy in stating this and mentioned that there are formal proofs to this effect.
- random314 4y agoI don't think this constitutes a formal proof on any way at all.
- JoshCole 4y agoThe formal proofs aren't in a Hacker News comment; just go read game theory research papers. For example, https://www.cs.cmu.edu/~noamb/papers/17-NIPS-Safe.pdf https://www.cs.cmu.edu/~noamb/papers/17-NIPS-Safe.pdf Or go try and solve a moderately complicated anything without allowing yourself abstractions with error. I won't wait on you, because your solutions will never terminate in my lifetime for even things as simple as chess which is a hell of a lot simpler than reality.
- JoshCole 4y agoTake the simplest problem of searching over a continuous range between zero and one exhaustively. Let the value you search for be 0.1. By a diagnolization argument we can realize that even a search carried on for an infinite amount of time and granted an infinite amount of space would not terminate. After all, to find 0.1 you need to make it past 0.01. But to reach that you have to reach 0.001. And so on. Let abstraction map from N to 1 over this space. As N goes up, abstraction error goes up, but the problem is no longer impossible because the diagnolization proof no longer holds. Let b be a branching factor in a game. As b goes to infinity, the game graph becomes continuous. In learning formulations under the game theoretic school of thought you have to search the game graph to get the average of your policies proportional to your counterfactual regret. That implies walking the continuous game graph. In reinforcement learning the bellman equations give you your values. This is also defined in terms of the game graph. So again we fall prey to the problem. We've shown that walking continuous things is impossible even under conditions that are ideal - infinite speed and memory and we've shown that this relates to the learning problem formulations I spoke of. Obviously this only gets worse when we impose reality - we don't actually have infinite space on our computers. They don't compute for an infinite amount of time either. But notice that before we searched for infinite space and time and we failed? When we move down to finite space and finite time we still have the property of completing after full enumeration. We have a finite amount of computing capacity. We have a finite amount of computational storage. Yet the growth rate for unabstracted game trees is exponential. Let c be our constraints. An abstracted game maps n states to one state. So it has log_n(X) where X is your state count. An abstracted game has X states. Since log_n(x) < X we know there exist terminating algorithms for abstraction that are not terminating for unabstracted because log_n(x) < X when X = c. So we get log_n(X) < c when X = c. This is actually much less than the real world gains. Since in learning we get the policy expectations multiple times over the game graph and the convergence guarantees relate to the complexity of the graph you get a much more worthwhile window than just the difference of log_n(X) versus X. For much tighter bounds check out game theory research. They get error bounds on the abstraction error too by choosing clustering solutions with provable properties. So it really has a much stronger formal treatment than you might imagine.
- moron4hire 4y agoI'm so sick of this "composition is so much better than inheritance" talking point that seems to have become dogma in the last 5 years. You use both. They are completely different things. Look at a classically inheritance-based system: a GUI library. You'll see lots of inheritance. Buttons and Checkboxes extend ClickableThing, ClickableThing extends Control. Whatever. And then you compose those controls on a Form. Look at a classically composition-based system: a video game entity-component system. You'll see Monsters composed of GraphicsObjects and Animations and WeaponSlots and AIAgents. And you implement all of those components in an inheritance hierarchy, or else your GameObjectThinger can't have a list of them that can grow or shrink at runtime. So keep saying "teach composition, not inheritance". You might as well tell musicians to study "rhythm, not tempo".
- sumy23 4y agoThose are good examples of inheritance. However, I think they'd be better served with mixins, which is another form of composition.
- sumy23 4y agoClass inheritance in OOP seems to be largely derived from such contrived examples as "Duck extends Animal." It's basically a worthless concept and OOP would be better without it. Composition over inheritance leads to much better code.
- lamontcg 4y agoYou still need to extract the right components and abstractions. And inheritance can be expressed in terms of composition, the base class(es) can be represented as composition and delegation instead (with a protected interface, a public interface and the implementation details all tightly coupled behind a single name which is what really makes it so poor).
- lamontcg 4y agoIt is useful to talk about "Bicycle inherits from Car with NumWheels set to 2" and "Boat inherits from Car with Surface set to WATER and not GROUND" as examples of Liskov violation.
- czx4f4bd 4y agoThe problem here is that that "a-ha!" moment is completely fallacious and not actually helpful. You think you've gained some deeper insight, but any attempt to apply that understanding is all but guaranteed to result in pain and frustration. The mental model that OOP objects map directly onto real physical objects plagued me for years, because I could not understand how I was supposed to translate it into real code. I finally broke through it after being forced to write a ton of enterprise Java, which helped me come to realize that classes and objects are useful units of abstraction for encapsulating related sets of data and behavior, as well as finally grasping the idea of composition and the utility of things like dependency injection, but I could've avoided years of pain if someone had actually explained that properly with concrete examples of useful object-oriented code. Since then, I've seen the same conceptual misunderstandings over and over from beginners and all of it comes down to the fact that these inane `Cat extends Animal` examples are simply wrong. > When you've never written a line of code in your life, abstract things like "network protocols" and "file I/O" and "ImageDisplay" (which is neither an image nor a display) are confusing, and so frustrating, and so not useful for teaching a complete novice. The solution here is not to teach them something that dooms them to even more frustration and confusion in the future. Also, if someone has never written a line of code ever, why are you teaching them OOP? If someone can't yet grasp concepts like network protocols and file I/O, OOP is literally not useful to them. It's like teaching someone calculus when they haven't even learned algebra yet. Start with the basics and then build up from there.
- glowingly 4y ago> It's like teaching someone calculus when they haven't even learned algebra yet. Start with the basics and then build up from there. I mostly agree in principle with the idea of building up a foundation. Going right into the deep end without decent guidance may leave one with horrible heuristics. However, (IMO) a crawl->walk->run abstraction does not always work well. I hate to say "it's case by case," but pedagogy is not easy. Algebra, IMO, should be taught either near or with its uses (modern calculus being one of them). Otherwise, one may be learning a bunch of abstract concepts without much reification.
- 4y ago