3

Problem:

We know that Java doesn’t allow to extend multiple classes because it would result in the Diamond Problem where the compiler could’t decide which superclass method to use. With interface default methods the Diamond Problem were introduction in Java 8. That is, because if a class implements two interfaces, each defining the same default method, and the implementing class doesn’t override the common default method, the compiler couldn’t decide which implementation to chose.

Solution:

Java 8 requires to provide an implementation for default methods implemented by more than one interface. So if a class would implement both interfaces mentioned above, it would have to provide an implementation for the common default method. Otherwise the compiler would throw a compile time error.

Question:

Why is this solution not applicable for multiple class inheritance, by overriding common methods introduced by child class?

Harmlezz
  • 7,972
  • 27
  • 35

3 Answers3

7

You didn’t understand the Diamond Problem correctly (and granted, the current state of the Wikipedia article doesn’t explain it sufficiently). As shown in this graphic,

A true diamond

the diamond problem occurs, when the same class is inherited multiple times through different inheritance paths. This isn’t a problem for interfaces (and never was), as they only define a contract and specifying the same contract multiple times makes no difference.

The main problem is not associated with the methods but the data of that super type. Should the instance state of A exist once or twice in that case? If once, C and B can have different, conflicting constraints on A’s instance state. Both classes might also assume to have full control over A’s state, i.e. not consider that other class having the same access level. If having two different A states, a widening conversion of a D reference to an A reference becomes ambiguous, as either A could be meant.

Interfaces don’t have these problems, as they do not carry instance data at all. They also have (almost) no accessibility issues as their methods are always public. Allowing default methods, doesn’t change this, as default methods still don’t access instance variables but operate with the interface methods only.

Of course, there is the possibility that B and C declared default methods with identical signature, causing an ambiguity that has to be resolved in D. But this is even the case, when there is no A, i.e. no “diamond” at all. So this scenario is not a correct example of the “Diamond Problem”.

Holger
  • 285,553
  • 42
  • 434
  • 765
  • I agree about the argument of shared state for the diamond problem, but non the less, if you would have support for multiple inheritance in *Java* you would have to deal with the problem of selecting one of multiple implementations of a single method. This problem is stated in the question and how it is solved for interfaces in Java 8. The same solution couldn't be guaranteed to be applied for classes. Or did I missed something? – Harmlezz Dec 21 '16 at 10:25
  • 2
    @Harmlezz: as stated in the last paragraph, the problem of having to disambiguate between multiple inherited non-`abstract` methods is a problem of multiple inheritance in general, but it doesn’t require a common super type to show up, hence, is unrelated to the *Diamond* problem. You are right, that this is a problem that can’t be solved generally for non-`interface` classes the same way, but still, it isn’t the specific problem called “Diamond Problem”. – Holger Dec 21 '16 at 10:32
1

Methods introduced by interfaces may always be overriden, while methods introduced by classes could be final. This is one reason why you potentially couldn't apply the same strategy for classes as you could for interfaces.

Harmlezz
  • 7,972
  • 27
  • 35
0

The conflict described as "diamond problem" can best be illustrated using a polymorphic call to method A.m() where the runtime type of the receiver has type D: Imagine D inherits two different methods both claiming to play the role of A.m() (one of them could be the original method A.m(), at least one of them is an override). Now, dynamic dispatch cannot decide which of the conflicting methods to invoke.

Aside: the distinction betwee the "diamond problem" and regular name clashes is particularly relevant in languages like Eiffel, where the conflict could be locally resolved for the perspective of type D, e.g., by renaming one method. This would avoid the name clash for invocations with static type D, but not for invocations with static type A.

Now, with default methods in Java 8, JLS was amended with rules that detect any such conflicts, requiring D to resolve the conflict (many different cases exist, depending on whether or not some of the types involved are classes). I.e., the diamond problem is not "solved" in Java 8, it is just avoided by rejecting any programs that would produce it.

In theory, similar rules could have been defined in Java 1 to admit multiple inheritance for classes. It's just a decision that was made early on, that the designers of Java did not want to support multiple inheritance.

The choice to admit multiple (implementation) inheritance for default methods but not for class methods is a purely pragmatic choice, not necessitated by any theory.

Stephan Herrmann
  • 7,963
  • 2
  • 27
  • 38