Live data from Hacker News

Goodbye, shitty "Car extends Vehicle" object-orientation tutorial

lists.canonical.org

31–40 of 134 posts

Re: Goodbye, shitty "Car extends Vehicle" object-orientation tutorial

#31
post #6

Earlier quoted context omitted.

You can explain is-a using examples that actually make sense to model using inheritance, like a set of game objects that have an interface like: class GameObject { public: // Called every frame to update the object's logical state. void Update(GameState* state); // Called to draw the object. Draw(GraphicsContext* context); } class EnemySpaceship : public GameObject { /* ... */ }; class SpaceDebris : public GameObject…

>rather than to make it a pointless ontological exercise of whether a Square is-a Rectangle or vice-versa it isn't pointless. It is the key point of the design : http://www.objectmentor.com/resources/articles/lsp.pdf

It is a key point in design AND it usually feels like a completely pointless and annoying waste of time.

Humans have such a marvelous natural facility for attaching a meaning to a sentence that we don't feel like loopholes and contradictions within language are meaningful. Ask the average person "who shaves the barber" in a describing of Russel's paradox and they'll give you a "what was the problem" look rather than any answer at all. see http://en.wikipedia.org/wiki/Barber_paradox

So squares versus circles doesn't seem like a slightly important problem till you have a variation of it starting out of your debugger.

And the other side of this is ... since teasing out these loopholes is really hard and so many exist in potentia, it might really be just as well to leave things confused and correct them as they come up. If you a square class that's not a subclass of a rectangle and your rectangle class has an isSquare method and a toSquare method, well, your code will screwy but you'll have saved thousands of dollars in training fees...

Re: Goodbye, shitty "Car extends Vehicle" object-orientation tutorial

#32

> You can’t add code to ducks. You do if you are creating a piece of software to track ducks. I don't get the impression that the person who wrote this ever had to seriously teach software development to software developers. Simplistic metaphors are used so frequently for this kind of thing because it prevents the learner from having to ascend more than one conceptual hurdle at a time. The alternative that he's propo…

I agree without caveats. "Car extends vehicle" and "duck extends bird" are great examples for the type of lesson they're trying to teach. I'm surprised people have time in their lives to worry about this crap. edit: Also, what's up with the title for this submission?

I worry about it because I learned inheritance from using it. I wish I had learned from a teacher. Instead I made hack work-arounds for something that I didn't realize was a common feature of OO languages. Until one day I did some poking and said "oh, THAT'S what extends and implements is for!"

Re: Goodbye, shitty "Car extends Vehicle" object-orientation tutorial

#33

Way back when I was first learning OOP, the typical "car extends vehicle" examples caused me not to see the practical point of OOP for a long time. I still resist using object-oriented approaches except in cases where the code demands it. (A feature, not a bug?) And, these days, if I do use OOP in places in the code, it's for encapsulation -- which is only a style consideration -- so the "car extends vehicle" example…

Yeah, I guess if I learned OOP with Java I'd hate it too. I look at phrases like "public class ModalWindow extends Window" and am very thankful I started with Python (and have learned Java where necessary, mostly to support Clojure).

Re: Goodbye, shitty "Car extends Vehicle" object-orientation tutorial

#35
I disagree with the arguments in general and find that modeling real world, common items is much more illuminating from a teaching/learning point of view. It would be an ridiculously long post to explain why, but here is an example picking one of the author's bullet points: "Penguins don’t implement the fly method that can be found in birds."

Should bird even have a fly method? Only if all birds fly. And the application will have penguins, so the answer is "no". This doesn't make the Duck extends Bird example a bad thing though. It points out that if you do shallow domain analysis, you will end up with a poor OO design where you shoehorn things like "fly" into penguins for example.

If some birds fly and some don't, some swim and some don't, some burrow and some don't, etc. you might implement this with "mix in" interfaces like "Flyer", "Swimmer", "Burrower", etc. This is a good lesson in how one can distribute different behaviors across a class hierarchy without polluting the common base interface of the hierarchy (i.e. without forcing all birds to fly). However, this burns the behavior into the concrete classes, prevents things like modeling the fact that baby (or dead) birds cannot fly/swim/burrow, and does not allow for sharing different fly/swim/burrow implementations across bird implementations (in languages like Java anyway). In other words, it shows why inheritance can be a good choice, and also a bad choice.

A common solution to this would be to use two hierarchies - one is the bird hierarchy that all birds implement (with behaviors like "preen feathers"). The other is the behavior hierarchy that all behaviors implement. Birds "contain" a list of behaviors. Code that operates on birds knows the bird interface has methods that make sense for all birds. Code that operates on behaviors like fly/swim/burrow would have behaviors passed in, or perhaps ask the animal in question "do you know how to fly?" and if yes, ask for its fly behavior. There are many variations on this, but the point is that there is a separation of concerns: bird concerns and behavior concerns. This helps teach the trade-off between inheritance and containment (e.g. behaviors not burned in through inheritance can be added/removed over time, for example, when a baby bird learns to fly).

The point though is that this kind of example (Duck extends Bird) helps one understand how to model real world items so they match the domain, to learn about separation of concerns, learn the pros/cons of inheritance/containment, design patterns, and perhaps most importantly, do so using concepts most people will more readily understand (cars or birds or people).

Re: Goodbye, shitty "Car extends Vehicle" object-orientation tutorial

#37

I disagree with the arguments in general and find that modeling real world, common items is much more illuminating from a teaching/learning point of view. It would be an ridiculously long post to explain why, but here is an example picking one of the author's bullet points: "Penguins don’t implement the fly method that can be found in birds." Should bird even have a fly method? Only if all birds fly. And the applicat…

Indeed.

The example with Birds, Ducks, and Penguins is much more colorful and fun then example with GUI widgets. It sticks. Students will remember ducks & penguins, but fall asleep before you even finish describing that boring GUI system.

Plus, nothing prevents you from using the same fun example to illustrate the second point. E.g. you can show that while penguin is a bird in real world, in your application Penguin might actually inherit from Pinniped, because it behaves like one (and it's "behaves-like", not "is-a" that we care about).

Re: Goodbye, shitty "Car extends Vehicle" object-orientation tutorial

#38
post #8

Earlier quoted context omitted.

If it teaches people to think of object-oriented programming as world-modeling, it is not a great lesson. Polymorphism is an abstraction technique whose goal is substitutability . "Car extends Vehicle" is useful if other kinds of Vehicles can be substituted for cars. If you teach someone that there is value in making Car extend Vehicle just because that expresses a real-world relationship, you are teaching exactly th…

Yes, you're right, it's only a great lesson if it's taught properly. I mean, really? Doesn't that seem like hair-splitting to you? In my opinion, dickering about this is the equivalent of, "Yeah, those two hortizontal parallel lines are a great symbol for equality as far as it goes, but really students need to understand the difference between equivalence and implication!" It's an equals sign. Same deal here. It's an…

I think the point is more that the analogy is so misleading, that it hurts the student's understanding.

A similar bad example would be using familiar round objects to teach equivalence: there are 10 apples, and 10 oranges, so apples == oranges.

Car's don't extend vehicles, and duck's don't extend birds. Just because we can organize these physical things into conceptual hierarchies based on their functionality, doesn't mean we can use them to understand polymorphism.

Re: Goodbye, shitty "Car extends Vehicle" object-orientation tutorial

#39
post #10
post #6

Earlier quoted context omitted.

You can explain is-a using examples that actually make sense to model using inheritance, like a set of game objects that have an interface like: class GameObject { public: // Called every frame to update the object's logical state. void Update(GameState* state); // Called to draw the object. Draw(GraphicsContext* context); } class EnemySpaceship : public GameObject { /* ... */ }; class SpaceDebris : public GameObject…

Most of the benefits of OO programming come from abstracting the machine / concerns (eg. MVC) rather than modeling the domain. (eg. Cars / Ducks / etc). I know it's just an example but it raises several important questions: Why does the GameObject need to know how to render itself? Why does the GameObject update the GameState which the GameObject is ostensibly also a part of? Does updating the GameState directly affe…

Code savings isn't a reasonable goal of OOP. Information-hiding (in which you take an arbitrarily-complicated method and abstract it behind a class) is.

Re: Goodbye, shitty "Car extends Vehicle" object-orientation tutorial

#40

Earlier quoted context omitted.

>rather than to make it a pointless ontological exercise of whether a Square is-a Rectangle or vice-versa it isn't pointless. It is the key point of the design : http://www.objectmentor.com/resources/articles/lsp.pdf

It is a key point in design AND it usually feels like a completely pointless and annoying waste of time. Humans have such a marvelous natural facility for attaching a meaning to a sentence that we don't feel like loopholes and contradictions within language are meaningful. Ask the average person "who shaves the barber" in a describing of Russel's paradox and they'll give you a "what was the problem" look rather than…

Please do tell of the occasion you found squares versus rects etc. staring at you out of the debugger. Because the solution to this problem depends on the behaviour you're trying to get, rather than some absolute solution, so philosophical argument about it always seemed pointless to me.

If the type is mutable, then per-instance information shouldn't be part of the class; have an isSquare calculated property or whatever. If the types are immutable, then it's OK to embed it in the class hierarchy. If you must have mutable types but you still want to embed it in a polymorphic hierarchy (most usually because of dynamic dispatch reasons, rather than if-casing logic on isSquare), then add a layer of indirection: have SquareBehaviour vs RectBehaviour, as needed. Whatever your solution demands, there's a way of doing it. What the solution doesn't need - nor even cares about - is the philosophical argument.

Post reply on HN