aspose file tools*
The moose likes Java in General and the fly likes Banning concrete inheritance Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Java in General
Bookmark "Banning concrete inheritance" Watch "Banning concrete inheritance" New topic
Author

Banning concrete inheritance

Mr. C Lamont Gilbert
Ranch Hand

Joined: Oct 05, 2001
Posts: 1170

Originally posted by Ilja Preuss:


Can you give us an example of an occasion where inheriting the type from a class got you into trouble? Did you violate LSP, or something?


Yes LSP is the issue. LSP says all implementors of methodx() should behave the same. The purpose of overriding is to change. In light of this, how can one ever justify overriding of methodx()?

If the implementation is different how can it not violate LSP? Sure, you may change methodx over time as you improve its implementation. And siblings may have different implementations. But there should never be a verticle difference in implementation. i.e. a siblings implementation would be different but a child's implementation would be 'changed.'


Either change would solve this;
  • no more inheritance of types.
  • no overriding of methods (no concrete inheritance)


  • Banning 'b' would eliminate the ability to change the behavior of a parent class. Banning 'a' would give the appearance of 'b' since you could never see the parent class.
    Michael Ernest
    High Plains Drifter
    Sheriff

    Joined: Oct 25, 2000
    Posts: 7292

    LSP -> Liskov Substitutability Principle

    I like Bertrand Meyer's definition: a subtype should require no more and promise no less than its supertype.


    Make visible what, without you, might perhaps never have been seen.
    - Robert Bresson
    Mr. C Lamont Gilbert
    Ranch Hand

    Joined: Oct 05, 2001
    Posts: 1170

    Originally posted by Michael Ernest:
    LSP -> Liskov Substitutability Principle

    I like Bertrand Meyer's definition: a subtype should require no more and promise no less than its supertype.


    Yes. After considerable thinking I can't come up with a scenario where a child class overrides a parent class's implementation without violating LSP

    I just thought of one: cut and paste
    [ September 14, 2005: Message edited by: Mr. C Lamont Gilbert ]
    Ilja Preuss
    author
    Sheriff

    Joined: Jul 11, 2001
    Posts: 14112
    Originally posted by Mr. C Lamont Gilbert:
    Yes. After considerable thinking I can't come up with a scenario where a child class overrides a parent class's implementation without violating LSP


    What about overriding toString?

    Notice that Meyer talks about *promises*. A method doesn't need to *promise* any or all of it's implementation details. For example, HashMap might be implemented in a way that delivers keys in a certain order, but it doesn't *promise* that it does. So an implementation that delivers in a different order doesn't break LSP.

    In fact, Meyer is the inventor of DBC and the language Eiffel, which has a syntax for specifying the "promises" (called the contract).


    The soul is dyed the color of its thoughts. Think only on those things that are in line with your principles and can bear the light of day. The content of your character is your choice. Day by day, what you do is who you become. Your integrity is your destiny - it is the light that guides your way. - Heraclitus
    Michael Ernest
    High Plains Drifter
    Sheriff

    Joined: Oct 25, 2000
    Posts: 7292

    I'm not sure how you're thinking about it, Lamont -- or perhaps applying it -- but "requiring no more" I don't think means you can't augment the supertype interface. Rather, it means that you cannot do so and require that the client of the supertype be aware of it. At the same time, a subtype should not obscure or denature an existing service.

    I find this expression to be liberating rather than prescriptive, but it requires a difference in perspective between design contracts (i.e., how subsystems will work with each other) and execution contracts (i.e., response times, memory costs).
    Mr. C Lamont Gilbert
    Ranch Hand

    Joined: Oct 05, 2001
    Posts: 1170

    Originally posted by Ilja Preuss:


    What about overriding toString?

    toString, hashCode, equals, clone, they are all the same. They are not abstract just to make things easier, but they often lead to mistakes. How many forget to reimplement equals and/or hashcode? Are any of those methods useful in their default implementation?


    Originally posted by Ilja Preuss:

    Notice that Meyer talks about *promises*. A method doesn't need to *promise* any or all of it's implementation details. For example, HashMap might be implemented in a way that delivers keys in a certain order, but it doesn't *promise* that it does. So an implementation that delivers in a different order doesn't break LSP.

    In fact, Meyer is the inventor of DBC and the language Eiffel, which has a syntax for specifying the "promises" (called the contract).


    Well I suppose its not about LSP then. LSP is about substitutability. This is about implementation inheritance.

    You can justify making a fastCircle the sibling of a circle but you can't justify making a fastCircle the child of a circle even if the only difference is the fastCircle draws faster. Its added complexity.

    The child needs a reason to change the inherited behavior, but there can be none. If you find that a parent class has an implementation and a child class has one too, then you should remove the parents implementation and create a new child with it.

    Its how I feel and what I'm thinking at the moment. Its based on tossing ideas around for a long time in many notes I have on my computer. Its just recently since this topic started that I see this is the unifying idea of those thoughts. Often someone introduces a convincing counter point, so I am not closing off the possibility yet.
    Ernest Friedman-Hill
    author and iconoclast
    Marshal

    Joined: Jul 08, 2003
    Posts: 24184
        
      34

    To answer Ilja's question, the concrete inheritance problems I've gotten into have all been of the "refused bequest" kind. They're not problems that happen because of concrete inheritance, so much as problem that occur because you're forced to use concrete inheritance. The happen when you use a concrete type as a method parameter, or as a method return type.

    So if method M parameter of type T1, and type T1 uses, say, 16 bytes of member data. If one day you want to specialize T1 and pass a subclass T2 to M. It turns out that T2's implementation wants to be terribly different than T1's so that it doesn't actually need those 16 bytes of data -- it needs 16 other bytes. Now T2 has to be 32 bytes. "So what," you say. Well, I often find myself writing applications where millions of T1s and millions of T2s are created. Those 16 measly bytes can have a huge impact!

    If M took an interface I as a parameter, and both T1 and T2 inherited it, then we wouldn't have this problem at all.

    You can make a similar argument about returning concrete types. If a concrete type has a constructor, and also there are methods that return that type, then you can never let that method return a polymorphic type without the same wasted space.

    So this is why a language that allowed methods to only accept and return interface types seems to me like an excellent way to help young designers "do the right thing."


    [Jess in Action][AskingGoodQuestions]
    Jim Yingst
    Wanderer
    Sheriff

    Joined: Jan 30, 2000
    Posts: 18671
    [CLG]: toString, hashCode, equals, clone, they are all the same. They are not abstract just to make things easier, but they often lead to mistakes. How many forget to reimplement equals and/or hashcode? Are any of those methods useful in their default implementation?

    Sometimes, but not often. For example things like Enums would be fine with the default implementations of equals() and hashCode() since there's only one instance per value in a JVM. On the rare occasions the current defaults (in Object) are desireable behavior it would be very simple to explicitly provide implementations equivalent to those current defaults. Eg.

    The last could be facilitated with a convenience method put somewhere like the System class.

    Note that Enum does in fact override equals() and hashCode() with these implementations - adding only a final, so that subclasses don't waste time with alternate implementations.

    Cloneable is more problematic, and personally I never use clone() anyway. If I were able to redesign Java's cloning though, I'd probably take clone() out of Object and put it in Clonable where one would expect to find it - then provide a couple utility methods in System which could be used for typical implementations, like:

    Probably they'd best be native code implementations, much like we now have in Object's clone(). I haven't really thought this through though since I don't generally care much about clone(), other than to avoid it.
    [ September 15, 2005: Message edited by: Jim Yingst ]

    "I'm not back." - Bill Harding, Twister
    Michael Ernest
    High Plains Drifter
    Sheriff

    Joined: Oct 25, 2000
    Posts: 7292

    Originally posted by Ernest Friedman-Hill:

    ...This happens when you use a concrete type as a method parameter, or as a method return type.

    If a concrete type has a constructor, and also there are methods that return that type, then you can never let that method return a polymorphic type without...wasted space.

    So this is why a language that allowed methods to only accept and return interface types seems to me like an excellent way to help young designers "do the right thing."

    Ooh, I think the light went on for me. I didn't realize until now you were talking about what you're talknig about.

    Yes, I like this f'rinstance better. Constraining the method seems a more positive approach than forsaking the extends. It seems consistent to me with what a good, seasoned programmers wants to do anyway.

    I wrote design pieces of a Circle MUD in Java this way a bunch o' years ago. It was a genuine pain in the a**. For starters, it was far more work in the abstract than I initially expected -- I was fresh off a talk by Simon Roberts and a Fowler book, full of moxy and Guinness to do things right. But there wasn't enough stout I could carry in one trip from Safeway to make me jump at the chance to finish that project.

    There are several attendant problems I can think of now that are not yet accounted for in this philosophy. Alas, my code and notes are probably long gone....I'll have to muse on it and see if they come back.
    Michael Ernest
    High Plains Drifter
    Sheriff

    Joined: Oct 25, 2000
    Posts: 7292

    As a matter of fact, this topic comes close to articulating a sideways consequence of requiring interfaces for return types and parameters. Maybe we could call it the "bag-in-a-box-in-plastic-wrap" antipattern. In this example, you have an interface that lets you embed business logic in an EJB.

    So now you're not tied to a specific J2EE application server (never mind the specifics of the deployment business per product), but you *are* tied to using one of them. You chafe at this potential restriction, so you put your business logic in a POJO, and put your POJO in your EJB implementation.

    At that point, you've done (as I see it) a small amount of work for the present and a pretty substantial amount of work for change that may or may not come.

    It makes me wonder more loosely and tangentially about the half-life of any set of business rules: does all this packaging amount to betting $5 that the dice come up seven, but putting a $1 hedge bet on every other combination?
    Ilja Preuss
    author
    Sheriff

    Joined: Jul 11, 2001
    Posts: 14112
    Originally posted by Ernest Friedman-Hill:
    To answer Ilja's question, the concrete inheritance problems I've gotten into have all been of the "refused bequest" kind. They're not problems that happen because of concrete inheritance, so much as problem that occur because you're forced to use concrete inheritance. The happen when you use a concrete type as a method parameter, or as a method return type.


    Ah, yes. With that I can agree...

    So this is why a language that allowed methods to only accept and return interface types seems to me like an excellent way to help young designers "do the right thing."


    Well, yes, perhaps. On the other hand, it doesn't help them to really learn the lesson. Also, there is probably much more in "doing the right thing" than just using an interface type, so I'm not fully convinced that it would help much...
    Mr. C Lamont Gilbert
    Ranch Hand

    Joined: Oct 05, 2001
    Posts: 1170

    Originally posted by Jim Yingst:
    ...
    Sometimes, but not often. For example things like Enums would be fine with the default implementations of equals() and hashCode() since there's only one instance per value in a JVM. On the rare occasions the current defaults (in Object) are desireable behavior it would be very simple to explicitly provide implementations equivalent to those current defaults. Eg.

    The last could be facilitated with a convenience method put somewhere like the System class.

    Note that Enum does in fact override equals() and hashCode() with these implementations - adding only a final, so that subclasses don't waste time with alternate implementations.


    You are only saving a bit of typing for a very special case. Anyway, Enum was designed specifically with equals() in mind so it does not really count. Any singleton will not usually need to override equals. But consider plugin environments where multiple classloaders are in play. Even with one JVM default equals won't work.


    Originally posted by Jim Yingst:

    Cloneable is more problematic, and personally I never use clone() anyway. If I were able to redesign Java's cloning though, I'd probably take clone() out of Object and put it in Clonable where one would expect to find it - then provide a couple utility methods in System which could be used for typical implementations, like:

    Probably they'd best be native code implementations, much like we now have in Object's clone(). I haven't really thought this through though since I don't generally care much about clone(), other than to avoid it.

    [ September 15, 2005: Message edited by: Jim Yingst ]



    Clone is fine as it is. I recently posted in another thread how to use it. There is no other solution to what clone provides.

    But this is another point to support the issue here. The Cloneable interface is only used to tell the JVM to turn on Object.clone(). The fact that it leaks through into all child objects has folks thinking it should have methods on it. If there was no inheritance of interfaces when you extend a class then nobody would ever ask for methods on Cloneable.

    Forthermore, without concrete inheritance we wouldn't be discussing Cloneable
    Mr. C Lamont Gilbert
    Ranch Hand

    Joined: Oct 05, 2001
    Posts: 1170

    Another interesting case for this is arrays. Putting child types in parent type arrays that are backed by a child type array;


    Wouldn't happen under the scenario discussed here. That is, if children didn't have automatic type but only the type you declared for them. Then there would be no Child2 or Child1 types. Its interesting though that this problem exists as a result of type inheritance and not concrete inheritance.
    Ken Blair
    Ranch Hand

    Joined: Jul 15, 2003
    Posts: 1078
    So this is why a language that allowed methods to only accept and return interface types seems to me like an excellent way to help young designers "do the right thing."


    It's unfortunate our institutions of higher learning aren't teaching young designers to do the right thing. I say this as at the ripe age of 23 I'm going through them and I'm quite unimpressed. I've been forced to look to books, articles and forums to learn how things should be done. At this point the schooling is nothing more than a hindrance.

    *sigh*
    Mr. C Lamont Gilbert
    Ranch Hand

    Joined: Oct 05, 2001
    Posts: 1170

    Nothing beats a good teacher.
    Ernest Friedman-Hill
    author and iconoclast
    Marshal

    Joined: Jul 08, 2003
    Posts: 24184
        
      34

    Originally posted by Mr. C Lamont Gilbert:
    Nothing beats a good teacher.


    Her name is experience.
    Steve Morrow
    Ranch Hand

    Joined: May 22, 2003
    Posts: 657

    Her name is experience.
    ...and she wields a cudgel.
    Ken Blair
    Ranch Hand

    Joined: Jul 15, 2003
    Posts: 1078
    Nay, it is a sledgehammer.
    Ilja Preuss
    author
    Sheriff

    Joined: Jul 11, 2001
    Posts: 14112
    Depends on how you treat her, I'd say. I welcome her lessons, and I don't remember being hurt.
    Ken Blair
    Ranch Hand

    Joined: Jul 15, 2003
    Posts: 1078
    When experience comes in the form of a demo bombing in front of the company's owner, it hurts.
    Steve Morrow
    Ranch Hand

    Joined: May 22, 2003
    Posts: 657

    Depends on how you treat her, I'd say. I welcome her lessons, and I don't remember being hurt.
    You must be one of the fortunate few that never makes a bad decision...
    Tony Morris
    Ranch Hand

    Joined: Sep 24, 2003
    Posts: 1608
    'Experience' is a funny word. Specifically, that some suggest that 'experience' and 'time' are directly proportional and intrinsic. For example, "2 years experience" as if it somehow implies more experience than "1 year experience". I just noticed that this comment has the ability to digress, so I'll stop now


    Tony Morris
    Java Q&A (FAQ, Trivia)
    Ken Blair
    Ranch Hand

    Joined: Jul 15, 2003
    Posts: 1078
    I am meeting a great many programmers with 10+ years of experience and only 1 year of knowledge.
    Mr. C Lamont Gilbert
    Ranch Hand

    Joined: Oct 05, 2001
    Posts: 1170

    Originally posted by Ken Blair:
    I am meeting a great many programmers with 10+ years of experience and only 1 year of knowledge.


    Micromanagement vs. empowerment, guess which is envogue today?
    Ken Blair
    Ranch Hand

    Joined: Jul 15, 2003
    Posts: 1078
    Maybe I'm misunderstanding but I don't think that's quite the same thing. Where I work I've actually found that, in general, there's more of an attitude of empowerment than micromanagement. What I meant is that I'm finding I gave the average programmer much too credit. They don't bother to see how things work under the hood, don't bother to develop good practices or learn proper design principles, in general just don't bother to learn. They learned the bare minimum, the first year, and stick with that. The worst part is, most of the time they treat anything they don't know how to do as impossible, saying it can't be done so that their inferior method that they already know seems acceptable.

    That's what I mean by people with 10 years experience, 1 year knowledge. Sure, they've been doing it for 10 years, but they haven't learned anything in the last 9.
    Ilja Preuss
    author
    Sheriff

    Joined: Jul 11, 2001
    Posts: 14112
    Originally posted by Steve Morrow:
    You must be one of the fortunate few that never makes a bad decision...


    Far from. Bad decisions is to a great deal what I learn from. I just don't think it has to hurt.
    Ilja Preuss
    author
    Sheriff

    Joined: Jul 11, 2001
    Posts: 14112
    Originally posted by Ken Blair:
    When experience comes in the form of a demo bombing in front of the company's owner, it hurts.


    This is an interesting statement, because I don't think it *has* to. But this is getting really off topic, so perhaps we should start a new thread on it?
    Mr. C Lamont Gilbert
    Ranch Hand

    Joined: Oct 05, 2001
    Posts: 1170

    Originally posted by Ken Blair:
    Maybe I'm misunderstanding but I don't think that's quite the same thing. Where I work I've actually found that, in general, there's more of an attitude of empowerment than micromanagement. What I meant is that I'm finding I gave the average programmer much too credit. They don't bother to see how things work under the hood, don't bother to develop good practices or learn proper design principles, in general just don't bother to learn. They learned the bare minimum, the first year, and stick with that. The worst part is, most of the time they treat anything they don't know how to do as impossible, saying it can't be done so that their inferior method that they already know seems acceptable.

    That's what I mean by people with 10 years experience, 1 year knowledge. Sure, they've been doing it for 10 years, but they haven't learned anything in the last 9.



    True. Over my 10 years I have noticed that people tend toward the well defined jobs. The ones where they are sort of told what to do. And the open ones where you have to make things happen, people shy away from. Well most people.

    One thing I have learned as an automotive engineer which is my real job is that an engineers value is measured in how much he can get done versus how much information is provided. Actually I don't think management realizes this, but I believe it to be true based on their expectations.
     
    I agree. Here's the link: http://aspose.com/file-tools
     
    subject: Banning concrete inheritance