• Post Reply Bookmark Topic Watch Topic
  • New Topic

java does not support multiple inheritance. Is it a limitation to java?  RSS feed

 
Biraja Tripathy
Greenhorn
Posts: 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
java does not support multiple inheritance. Is it a limitation to java?
 
Joe Ess
Bartender
Posts: 9443
12
Linux Mac OS X Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Can you think of an instance where multiple inheritance is necessary?
 
Ernest Friedman-Hill
author and iconoclast
Sheriff
Posts: 24217
38
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
As this has nothing to do with Threads, I'm moving this to "Java in General (Intermediate)". Followups there, please.
 
Thomas Paul
mister krabs
Ranch Hand
Posts: 13974
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Java doesn't allow you to access beyond the end of an array. Do you consider that a limitation of Java?
 
Tim West
Ranch Hand
Posts: 539
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi guys,
Somewhat offtopic, on the subject of Java inheritance...it is a little limited, at least in my humble POV. Multiple implementation inheritance I can happily live without. However, why aren't privates inherited?? Why aren't member fields inherited?? Why can't static methods be overridden?
I know these topics have been the subject of a *whole* lot of talk and I wouldn't expect anyone to take the time to write an answer back (at least, not one that will convince me that Java's inheritance is ideal :-)), but if anyone has a pointer to some online discussion or articles on it, I'd be interested.
Cheers,
--Tim
 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
However, why aren't privates inherited??
Mostly because they're private. I mean, the whole point of calling a method or field private is to say that you can't access it from another class, period. Whereas the point of inheritance is to allow a subclass to access methods and sometimes fields of the superclass. Those are two incompatible goals. So they assume that if you declare something private, you don't want it to be inherited. If you wanted it to be inherited, you should use "protected" instead.
Why aren't member fields inherited??
They are.
Why can't static methods be overridden?
Well, you can create a static method with the same name and signature as a static method in the superclass - but we call it shadowing, not overriding. The term overriding includes the idea of using the invoking instance to do dynamic lookup to determine which version of a method should be called. For a static method, there's no invoking instance (at least, none is necessary) and so this type of dynamic lookup is impossible. Thus the behavior of static methods is different enough in this respect that Java's creators choose to avoid the term "overriding" to reduce confusion.
[ April 05, 2004: Message edited by: Jim Yingst ]
 
Tim West
Ranch Hand
Posts: 539
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Jim,
A bit of context - I'm coming from an Eiffel perspective. In terms of language design I think Eiffel's brilliant, though there are certainly performance tradeoffs in the handling of multiple inheritance - dynamic dispatch is much more common. Of course, I used Eiffel only for education; it has little real-world use...
As I'm writing this post I'm also realising that Java's approach is often just different to what I'd have previously written in Eiffel. I'll include my arguments here anyway though.
Private methods
What you say makes sense to me. What you say about incompatible goals is exactly what I'd have said, but immediately after I'd have said "so subclasses can see privates". This is how it's done in Eiffel. There are disadvantages to this, particularly in a language where you're frequently extending library classes. The onus is on the developer of the subclass to do so safely.
I admit that my issue with this is probably more a hangover from Eiffel than anything else, but I think that there are a lot of circumstances where you want a subclass to see stuff that no-one else (not even classes in the same package) can see.
More intuitively, I think that when you say "X is a Y", you mean X and Y behave the same internally as well as externally. If they don't maybe we should be interfacing, or using abstract methods.
Maybe in my ideal Java we'd ditch the 'friendly' scope which (AFAIK) is useless, in favour of a "semi-private" scope that allows only subclasses to view stuff.
In the absense of this, I'd contend that subclasses viewing privates actually leads to stronger encapsulation. That might sound dumb, but I'd say a developer writing a subclass can be trusted to use privates sensibly and safely more than a developer working elsewhere, even in the same package. Then, where appropriate methods could be declared private rather than protected. This theory relies on the assumption that a lot of use of 'protected' would be avoided by letting subclasses view privates.
Empirical evidence could prove me false on the entire previous paragraph, in one of several ways. Those are just my hypotheses.
Member fields
Ugh. I'm daft - you're quite right. Let me retract and instead ask: "Why can't I override member fields?" or equally, "What is benefit of shadowing rather than overriding".
I tried to write code examples that demonstrated why shadowing is so bad, but they were all immediately very dangerous pieces of code (they had no encapsulation). So I guess if you write "good" code, there is no real problem in shadowing.
So you're completely write. Instead I'll ask what I have above: what's the benefit of shadowing? Inheritance would be more logical to me if fields and methods were handled the same way.
Static methods
Well, there's no dynamic instance, but there's a dynamic type. Dynamic lookup should be equally possible (or at least that's my understanding). It's a design decision I guess, but I don't see the advantage in the way it's done in Java. The obvious example:

This prints Child then Parent. I found (when learning Java) that this adds significantly to the confusion - there are two methods that could be called, depending on the type of the reference...my feeling is that the object at the end of the reference should be the sole determinant of what method is called, that type of the reference itself should be irrelevant.
(Obviously the example above is trivial, if you're dealing with a collection of MyParents, with several different child types, the situation gets more interesting)
An aside
Eiffel's handling of all this is ideal in my (possibly warped) mind:
  • "public" fields can be read by other classes but never altered. Thus you essentially get an implicit "getter" and you write an explicit "setter" when you want one. Encapsulation is enforced, except for subclasses (see below).
  • All fields, private or public, are inherited. You can override them in a subclass and code in either place refers to the one single value.
  • A method with no parameters can be overridden by a field of the same type, and vice-versa. From a client perspective, there's no difference between a method with no parameters that returns an int, and an int field. This requires point one above.
  • There's no "protected" but you can selectively allow access to a method or field to individual classes.
  • Multiple inheritance is fine, but much nicer than C++ - no precedence rules, you can explicitly rename methods and keep both of them when a duplication occurs.


  • The bottom line is that fields and methods are handled identically, encapsulation is absolutely enforced except for subclasses (big exception, maybe...) and inheritance happens intuitively (for me, at least).
    Eiffel has no notion of 'static'. For anyone who knows Eiffel, by 'public' and 'private' I mean feature{any} and feature{none} respectively.
    Anyway, these are my thoughts. Gawd, what a long post!
    --Tim
    [ April 05, 2004: Message edited by: Tim West ]
    [ April 05, 2004: Message edited by: Tim West ]
    [ April 05, 2004: Message edited by: Tim West ]
     
    Randall Twede
    Ranch Hand
    Posts: 4696
    8
    Java Scala
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    actually, java does allow a limited form of multiple inheritance. you can implement as many interfaces as you want to. like Thomas' somewhat sarcastic comment about arrays, this is an example of Java learning from the "mistakes" of C
     
    Maulin Vasavada
    Ranch Hand
    Posts: 1873
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Hi Joe Ess,
    Yes. At one place I think we needed "multiple inheritance".
    We had a GUI to represent a workflow,
    - to store the definition of the workflow I defined Task object
    - In GUI I needed to display those Task objects. Now this Task.java represented task Definition but in GUI I must store some GUI specific things along with the GUI Task.
    - But GUI Task has to extend a little panel or something (I forgot as my colleage did that implementation)
    - Hence logically my GUI Task = my backend Task (that is Task.java) + GUI Panel
    It made sense to extend GUI Task from Task.java object as it was sure a "is a" relationship but we couldn't do it because of lack of multiple inheritance. We had to use "has a" relation instead and delegate all the calls to Task.java object for configuration settings...
    In this scenario I thought multiple inheritance would solve the problem the way logically we were thinking about things...
    Now, I am aware of confusions arise from multiple inheritance and all but I just wanted to share the experience...
    Regards
    Maulin
     
    Randall Twede
    Ranch Hand
    Posts: 4696
    8
    Java Scala
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Maulin,
    i'm guessing your Task class extended class Object by default? if so, you can obtain needed functionality by having Task extend Panel (even though class Task doesn't need any of the things it inherits), then have GUITask extend Task.
    [ April 10, 2004: Message edited by: Randall Twede ]
     
    Maulin Vasavada
    Ranch Hand
    Posts: 1873
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Hi Randell
    I can't extend Task from Panel because Task is supposed to be pure backend object which my backend can interpret. It would be meaningless for Task to extend from Panel as my backend doesn't need Panel. Its the GUITask which needs to be both- Task and Panel
    Basically, the GUI maintains Task[] in Workflow Object and then passes to the backend which manages things...
    If I could do Task extends Panel, I would have certainly do it
    Regards
    Maulin
     
    Marilyn de Queiroz
    Sheriff
    Posts: 9082
    12
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Sounds like maybe an interface would help.
     
    sever oon
    Ranch Hand
    Posts: 268
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    What are the advantages of inheritance that you're trying to exploit by using MI? There are a few big ones as far as I can see. When a class Sub extends another class Base:
  • objects of type Sub can be polymorphically treated as objects of type Base.
  • changes in method bodies in Base are *automatically* inherited by Sub, without having to update code in Sub.
  • if ref instanceof Sub == true, then ref instanceof Base == true as well.
  • Sub can override methods in Base


  • If a class Sub extends another class Base, then it meets all of the above criteria. If you have a situation where you need a particular Sub to have this relationship with Base1, Base2, and Base3 (very rare indeed), then you have a case of MI on your hands.
    Many people will probably reply to your question with the age-old answer, "Prefer aggregation to inheritance". It's true that you can draft a good design that will use aggregation in place of MI in most cases. However, in some cases, you might prefer MI because you want *all* of the above conditions to be true for Sub wrt Base1, Base2, and Base3. In those cases, simple aggregation will not get you that.
    However, you can effectively get MI in Java if you use a combination of a more complex form of aggregation and interfaces. Basically, you have to separate the interfaces of the classes from their implementations, and then aggregate all of the Base class implementations in the subclass and manually forward the calls. It's complicated, but it gets you a Sub that follows all of the above listed rules with respect to multiple base classes, and if you need it, you need it. Here ya go:

    Notice I've marked the AbstractSub class protected (at the class level). This, of course, will not compile (classes can't be marked protected), but it gets across the point of what I'd like to do. Unfortunately, cuz you can't have a protected class, you'd have to go ahead and mark it public and just explain in the doc that no one should ever, ever, ever create references of type AbstractSub--they should always use references of type Sub instead.
    This is because I don't ever want code in the system to deal with objects polymorphically as type AbstractSub--instead, all subclasses of AbstractSub can be polymorphically treated as type Sub, the interface type. AbstractSub therefore is specified only for one purpose: to act as a code container for subclasses to inherit all of that messy aggregation code. This is why I provided the Sub interface above, even though it is not strictly necessary (it could be deleted and AbstractSub could have simply implemented Base1, Base2, and Base3 instead): it provides a way for other code to treat Sub1, Sub2, and Sub3 polymorphically without having to decide between one of the supertypes Base1, Base2, and Base3. What if a client wants to create an array of subs and call foo(), bar(), and baz() on each element without a bunch of messy typecasting? Can't be done without the Sub interface--since that's there, though, one could simply write:

    Now let's go through the check list to see if we've hit all the points:
    Can Sub1, Sub2, and Sub3 all be treated polymorphically as type Base1, Base2, and Base3? Yes.
    Will changes to method bodies in any of the Base classes be automatically inherited by Sub1, Sub2, and Sub3? Yes.
    If (ref instanceof Sub) == true, is (ref instanceof Base1 && ref instanceof Base2 && ref instanceof Base3) == true? Yes.
    If Sub1, Sub2, or Sub3 provide foo(), bar(), or baz(), will these methods override the Base implementations? Yes.
    Because all of these conditions are satisfied, we can consider any class that extends AbstractSub as having multiply inherited from Base1, Base2, and Base3 in every way.
    One of these days, when I get time I'm going to see if there's a good way to implement this MI stuff using Java 1.5's new metadata facility. Probably not very useful, but loads of fun I'm sure.
    This is a mighty long post, so I might come back and address some of the other interesting points in this thread in subsequent posts.
    sev
    [ April 11, 2004: Message edited by: sever oon ]
     
    sever oon
    Ranch Hand
    Posts: 268
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Why can't privates be inherited?
    I believe it's proper that privates are not inherited. This affords you a bit more power in terms of requiring subclasses to follow the contract of your class. Look, if I write an Address class:

    Now I've forced all subclasses for all time to access the zipCode field by calling getZipCode() instead of just accessing the field directly with zipCode. This is a Very Good Thing...here's why. Someone comes along and extends this class:

    Note they had to call getZipCode() in getZipPlus4() instead of just saying zipCode + "-" + .... Now, let's say I come along and want to extend Zip4Address to light up a zip code region on a US map every time the zip code of an address is accessed:

    Now, when I instantiate a MapHighlightingAddress, every time I call getZipCode() *or* getZipPlus4(), the map gets highlighted, which is exactly correct. If in the Address class I had marked the zipCode field protected, I would have allowed the Zip4Address class to use it directly in their getZipPlus4() method...meaning that in MapHighlightingAddress I would not only have to override getZipCode(), but also getZipPlus4(), to ensure the map gets highlighted for either call. What if there were 100 methods in Zip4Address, though, that required the zipCode? Then, if I want the proper functionality in MapHighlightingAddress to work, I have to override all 100 of them! This is ridiculous, though, because they're all accessing the zipCode field and I should therefore only have to override that one method. So much for code reuse.
    By marking the field private, though, and requiring subclasses to use the method getZipCode(), I ensure that this point of extension will always be avialable to subclassers no matter how long the inheritance hierarchy gets. The other way of doing things does not promote code reuse and is pretty hostile, requiring subclassers to potentially duplicate code in 100 methods to get proper functionality. Ugly.
    sev
     
    sever oon
    Ranch Hand
    Posts: 268
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Why aren't member fields inherited?
    They are, of course, except for private members which allows for variable shadowing. (I believe Jim Yingst's earlier use of the term "shadowing" when talking about static methods is incorrect...I'll explain why later.) This is because as a subclass developer, you may only have access to the public API and API docs of a class you are extending, and therefore have no idea what private variables that class has and what they are called, nor should it affect you. Consider this experiment:

    Now, uncomment Bar.getBaz() and rerun the program. If you consider what's going on there, you'll see that it makes perfect sense because Bar should feel free to name its private variables whatever it wants to without concern for some lurking private in a superclass it has no way of knowing about.
    Now on to static methods...
    Why can't static methods be overridden?
    Static methods cannot be overridden because you call them on a particular *class*, not an instance. Consider the following code:

    In the main() method above, how could one possibly invoke those static methods in a virtual way? It's impossible--if you call a class method, you have to specify the class! Since you never specify an object reference, there's no notion of typecasting or virtual methods involved. You're specifying the exact class on which the method should be invoked, and that's the end of it. So I don't see Bar's static method as "shadowing" Foo's...they're just totally different methods that happen to be named the same, but there's never any ambiguity as to which one is being called that requires rules to resolve.
    Ah, but of course, it's never that simple. Java also allows you to invoke static methods on *object* references, not just class references as I've shown above. Why they decided to allow this is far beyond me, I can't think of a good reason for it at all. All it does is befuddle people who are trying to learn about static methods and variables.
    For example, if someone decides they are going to use object references to invoke static methods, you run into all sorts of crazy things:

    If you came upon this Example class and weren't familiar with this code base, just from looking at line 1, a reasonable person would expect a NullPointerException to be thrown because you're calling a method on f, a null reference. Or that's how it appears. Actually, it works just fine and prints out "foo".
    Moving on, when you come to line 2 you're really flummoxed. f points to an object of class Bar, but because you're using a reference of type Foo to access that object, it is polymorphically being treated as a Foo. So which class' static method will be called? Does it depend on the class of the object, or the type that is conferred upon it by the reference used? It's impossible to say without actually running the code. If you do run it, you'll see it prints out Foo.
    Now, imagine that lines 1 and 2 were written sensibly by the original programmer:

    Suddenly, the behavior of the program is obvious and all that ambiguity about NPEs and class vs. type distinctions disappears in a cloud of smoke. This leaves me wondering, why would anyone ever want to use an object reference to refer to class data/methods??? Why is it allowed in Java at all?
    sev
     
    Jim Yingst
    Wanderer
    Sheriff
    Posts: 18671
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    I believe Jim Yingst's earlier use of the term "shadowing" when talking about static methods is incorrect
    You are correct; the proper term is hiding, not shadowing. Annoying since I knew that, but hadn't thought about it in a while. Ah well. Thanks.
     
    • Post Reply Bookmark Topic Watch Topic
    • New Topic
    Boost this thread!