3

I'm a Java developer and I've been learning C++ on the side. I recently got into the "deadly diamond of death" in C++ and researched if this problem was possible in Java. In Do interfaces solve the "deadly diamond of death" issue?, I found this:

Java 8 screws this up for methods; an interface now can declare both default methods and static method implementations. This brings a large chunk of the Diamond of Death problem into the language.

I'm wondering if someone would be able to expand on the problems introduced by Java 8 for the DDD.

Ousmane D.
  • 54,915
  • 8
  • 91
  • 126
JNMN
  • 165
  • 9
  • 1
    *Default interface methods* introduced a kind of *multiple inheritance* to Java8 which is the root cause of the DDD problem... – Timothy Truckle Dec 31 '17 at 13:09
  • 1
    There's no DDD because if there's an ambiguity it won't compile. See https://stackoverflow.com/a/24401182/1898563 – Michael Dec 31 '17 at 13:10
  • 4
    Why has this been closed as "unclear"? What is unclear about it? – Oliver Charlesworth Dec 31 '17 at 13:24
  • 8
    Whoever wrote the quoted bit is (a) doesn't really understand the difference between Java's multiple inheritance and C++'s and (b) is choosing to be alarmist over being clear or helpful. Java always had multiple inheritance of _types_. Java 8 adds multiple inheritance of _behavior_. DDD problems stem from multiple inheritance of _state_, which Java does not have. – Brian Goetz Dec 31 '17 at 15:39
  • 4
    @BrianGoetz With Java's multiple inheritance, DDD stands for the Diamond of Decreased Distress. – Stuart Marks Dec 31 '17 at 18:36

2 Answers2

10

I imagine the quoted answer is referring to scenarios such as this in Java:1

interface B {
    default void x() { System.out.println("B::x"); }
}

interface C {
    default void x() { System.out.println("C::x"); }
}

class D implements B, C {}

What would something like new D().x() do here?

Luckily, the compiler forbids the definition of D entirely, with the following message:

D inherits unrelated defaults for x() from types B and C

One can resolve the ambiguity (and satisfy the compiler) by overriding x in D. One may then explicitly invoke the individual inherited default methods:

class D implements B, C {
    @Override
    public void x() {
        B.super.x();       // Note explicit interface names
        C.super.x();
    }
}

1. Clearly, there's no diamond here. But this is an even simpler case. We could add interface A { void x(); } that both B and C extend, but that wouldn't change the result.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • What if class D is written to implement B and C at a time when they don't have default methods, and is successfully compiled, but is then dynamically loaded into a program where B and C have default methods? – supercat May 09 '20 at 16:55
7

There are three resolution rules that prevent the diamond problem:

Stated in the Java-8 in Action book:

  1. Classes always win. a method declaration in the class or a superclass takes priority over any default method declaration.

  2. Otherwise, sub-interfaces win: the method with the same signature in the most specific default-providing interface is selected. (If B extends A, B is more specific than A).

  3. Finally, if the choice is still ambiguous, the class inheriting from multiple interfaces has to explicitly select which default method implementation to use by overriding it and calling the desired method explicitly.

If for some reason there remains any ambiguity then your code will simply not compile.

Ousmane D.
  • 54,915
  • 8
  • 91
  • 126