Do interfaces solve the "deadly diamond of death" issue?
Asked Answered
P

7

5

Do interfaces solve the deadly diamond of death problem?

I don't think so, for example:

// A class implementing two interfaces Interface1 and Interface2.
// Interface1 has int x=10 and Interface2 has int x = 20

public class MultipleInterface implements Interface1, Interface2{

    public void getX(){
        System.out.println(x);
    }
}

Here we get an ambiguous x.

Though interfaces are a good way for solving method ambiguity, I guess they fail in the case of variables?

Am I correct? If I am missing something, enlighten me.

Permanganate answered 25/3, 2012 at 14:14 Comment(1)
Java always had diamonds, since Java had multiple inheritance of types from day 1 (interfaces B and C extend A, then class D implements both B and C). But these diamonds were always of the non-deadly variety. Java 8 adds multiple inheritance of behavior, but this is again non-deadly, because its impossible to inherit two different implementations of the same method.Spreadeagle
M
4

Java prevents multiple concrete/abstract class inheritance, but not multiple interface inheritance. With multiple interface inheritance you inherit abstract methods, not implementation. See this post with a good explanation and examples: https://web.archive.org/web/20120724032720/http://www.tech-knowledgy.com/interfaces-sovles-diamond-death/

Macintosh answered 31/3, 2012 at 10:21 Comment(2)
very useful link. It solves my query. So I get it as, even though diamonds can occur in case of interfaces, there will be no diamond of death. Thanks :)Permanganate
yes because Java is from the root not designed for Multiple Inheritance as there is only one super parent Object in Java, therefore Java solves this by Multiple Interface InhertanceMacintosh
E
14

When a class inherits two variables from parent interfaces, Java insists that any use of the variable name in question be fully qualified. This solves the problem. See the Java Language Specification Section 8.3:

It is possible for a class to inherit more than one field with the same name. Such a situation does not in itself cause a compile-time error. However, any attempt within the body of the class to refer to any such field by its simple name will result in a compile-time error, because such a reference is ambiguous.

A similar statement applies with respect to interfaces (JLS §9.3).

The sample code in the answer by Óscar López is excellent. Here's another example:

class Base {
    int x = 10;
}

interface Interface {
    int x = 20;
}

class SingleInheritance implements Interface {
    int y = 2 * x; // ok
}

class MultipleInheritance extends Base implements Interface {
    int y = 2 * x; // compile-time error
    int z = 2 * Interface.x; // ok
}

void aMethod(MultipleInheritance  arg) {
    System.out.println("arg.x = " + arg.x); // compile-time error
    System.out.println("x = " + Interface.x); // ok
}

Edit

Java 8 introduces a limited form of multiple inheritance for methods because interfaces now can declare default methods that subinterfaces and implementing classes can inherit. Since a class can implement multiple interfaces, this can cause ambiguities because distinct default methods with the same signature could be inherited from multiple interfaces.1 Java deals with this using a priority scheme to specify which default method is actually inherited. It requires explicitly overriding inherited default methods when the priority scheme fails to yield a single winner.

Note that in no case does Java have a Diamond problem, which is a very specific subclass of problems that can come with multiple inheritance.2 The "Diamond" part refers to the shape of the class inheritance diagram that's required in order to have the problem. In C++, the Diamond problem can arise if a class A inherits from two classes B and C, each of which inherits from a common base class D. In that case, any public members of D ends up appearing twice in A—once inherited through B and once through C. Also, whenever an instance of A is constructed or destroyed, the constructor or destructor for D ends up being called twice (often with disastrous consequences, hence the "of death" part of the name). C++ solves these issues by providing virtual inheritance. (See the discussion here for details.)

1 Note the use of the word "distinct". There is no issue if the same default method is inherited through two parent interfaces that in turn extend a common base interface where the default method is defined; the default method is simply inherited.

2 Other multiple inheritance issues—like the ambiguities that can arise in Java with interface fields, static methods, and default methods—technically have nothing to do with the Diamond problem (actually, the Deadly Diamond of Death problem). However, much of the literature on the subject (and an earlier version of this answer) ends up lumping all multiple inheritance problems under the rubric "Diamond of Death." I guess the name is just too cool to be used only when technically appropriate.

Enactment answered 25/3, 2012 at 14:18 Comment(10)
Could you show with code what you mean? To my knowledge variables cannot be inherited from interfaces.Milkandwater
I think Oscar spelled it out perfectly.Dearing
Can you comment on what specific problematic scenarios you're imagining wrt the "Edit" section about Java8? (FYI, this answer is quoted in this question.)Joanne
@OliverCharlesworth - The issue is that classes can now inherit behavior from two or more parent. Suppose interfaces A and B each specifies (or inherits) a default method foo(). Now concrete class C is declares to implement both interfaces A and B. Then C has inherited two behaviors, a classic Diamond of Death scenario. It must implement its own method foo() that explicitly invokes the foo() of one of its parents. (Java 8 does have an exception in the case that C all inheritance paths are to the same behavior, so DoD is partially dealt with automatically.)Enactment
@OliverCharlesworth - Google "Java 8 diamond of death" for lots of discussion of this issue. See, for instance, the blog post Java doesn’t have “Diamond” problem : Really ..?.Enactment
@TedHopp - Indeed. I guess I don't really see this as a problem, in the sense that the compiler forces you to disambiguate explicitly.Joanne
@OliverCharlesworth - You're right. Technically, Java 8 doesn't have a DoD problem. Instead, it has more complicated language rules to address the DoD problem it would otherwise have. :)Enactment
@TedHopp Virtually everything said about Java in that section is incorrect.Spreadeagle
@BrianGoetz - I've rewritten my answer to eliminate the suggestion that Java has a DoD problem. I believe the "of death" part of the name comes from C++ and the Very Bad Things that can happen when base class constructors or destructors are called multiple times whenever a descendent class instance at the bottom of a diamond inheritance structure is created or destroyed. At least this aspect of the problem has nothing to do with multiple inheritance of state.Enactment
@TedHopp Indeed, not all diamonds are deadly, and not all problems with multiple inheritance require diamonds. I'd correct slightly; Java has had multiple inheritance from day 1; what's new is that along with the type and interface contract, in Java 8 subclasses can also inherit behavior that implements that contract. So Java has always had diamonds, which were deadly neither before nor after Java 8. And without multiple inheritance of state, many other multiple-inheritance pitfalls (including the need for virtual vs nonvirtual base classes) go away.Spreadeagle
D
12

An interface can't have attributes. When you write this:

public interface Foo {
    int x;
}

Under the hood it implicitly gets converted to a constant, something like this:

public interface Foo {
    public static final int x;
}

Let's say you have another interface with a similarly named constant:

public interface Bar {
    int x;
}

And if you were to use the x value in a class that implements both Foo and Bar you'll have to qualify those constants, leaving no room for ambiguities, like this:

public class Baz implements Foo, Bar {
    private int y = Foo.x + Bar.x;
}

So no diamond in here. Anyway, declaring constants in an interface is frowned upon nowadays, most of the time you're better off using an enumeration for the same effect.

Dispense answered 25/3, 2012 at 14:24 Comment(2)
If a constant declared in an interface is a useful object and not simply an int value, then using an enum isn't particularly convenient. The real error, I think, is using implements instead of import static to bring constant names into the local name space. (With legacy code, though, you just have to work with what you inherit (so to speak).)Enactment
@TedHopp Agreed. for simple cases (int constants) an enum might be a better idea, for more complex values import static is the way to go, but I'd rather define my constants in a class and not an interface, it can be confusing as is evidenced by this questionRoseberry
D
5

No, you don't. Interfaces don't have any variables, other than static final ones.

If you actually write, compile, and execute those interfaces and classes you'll have your answer. That x variable is not a class member, so there's no ambiguity.

This is one of those questions that you can easily answer for yourself by writing the code and letting the JDK tell you. It'll be faster than asking here.

Dearing answered 25/3, 2012 at 14:21 Comment(2)
Completely agree with you. But since I asked this question here, I got some very good points like, using import static, and using enumeration rather than constants in interface(as mentioned by other users). Don't u think I got something EXTRA to learn? & don't u think this is going to help me or somebody else? I am not trying to waste somebody's time here. If anybody feels like they can share some knowledge with me, they should... otherwise, simply ignore my question. People like me, who are beginners in programming need help from great programmers like u, sir. Please encourage us to ask :)Permanganate
You don't get to control how I answer any more than I can control what you ask. I don't encourage or discourage questions; I just offer my opinion for your consideration. Please leave the attitude at the door, Biman. Thanks.Dearing
M
4

Java prevents multiple concrete/abstract class inheritance, but not multiple interface inheritance. With multiple interface inheritance you inherit abstract methods, not implementation. See this post with a good explanation and examples: https://web.archive.org/web/20120724032720/http://www.tech-knowledgy.com/interfaces-sovles-diamond-death/

Macintosh answered 31/3, 2012 at 10:21 Comment(2)
very useful link. It solves my query. So I get it as, even though diamonds can occur in case of interfaces, there will be no diamond of death. Thanks :)Permanganate
yes because Java is from the root not designed for Multiple Inheritance as there is only one super parent Object in Java, therefore Java solves this by Multiple Interface InhertanceMacintosh
J
0

Deadly Diamond Of Death Problem.

class A
{
void eat()
{
    print("I am eating Apple")
}
}

class B and C extend A and Override eat() method

class B extends A
{
void eat()
{
print("I am eating Banana")
}
}


class C extends A
{
void eat()
{
print("I am eating Grapes")
}
}

Now if java had multiple Inheritance ? what will Happen in the following case.

 class D extends B ,C
{
//which eat() method will be inherited here for class D ? a problem  ? ?
}
Jelks answered 2/4, 2013 at 11:52 Comment(3)
The class D declaration is not legal Java. A class cannot extend two base classes.Enactment
yes that is what is explained "IF" java allowed multiple inheritance, It would have caused problems.Jelks
How is your answer relevant to the question? (It was not a question about the definition of the Deadly Diamond of Death, but about whether Java interfaces avoid it in all cases.)Enactment
D
-1

The Deadly Diamond of Death is a problem with variables, but an even bigger problem with virtual methods. If classes Moo1 and Moo2 were to both inherit from class Foo and override abstract virtual function Bar, and if a class Zoo were allowed to inherit from Moo1 and Moo2, without having to add its own override of Bar, it it would be unclear what method Bar of a Zoo should do. Interfaces avoid that issue by requiring that every class that implements an interface must supply its own implementation for all of the interface members, and by specifying that all members of an interface will be considered identical in all interfaces which extend it directly or indirectly. Thus, in the above situation, if Foo, etc. were interfaces rather than classes, then any class which implements Zoo would be required to implement Foo.Bar, which would be synonymous with Moo1.Bar, Moo2.Bar, and Zoo.Bar.

Dareen answered 2/4, 2013 at 16:33 Comment(5)
Actually, the "deadly" part of the Deadly Diamond of Death (at least in C++) is related to non-virtual destructors. In your example class structure, when an instance of Bar is destroyed, the (non-virtual) destructor for Foo would end up being called twice (with possibly disastrous consequences). Virtual destructors in C++ help with the problem; they do not cause it.Enactment
@TedHopp: That's a C++ problem. A language which simply didn't have non-virtual destructors or (like Java) doesn't have destructors, period, could avoid that issue. The cited ambiguity, however, is much more fundamental, and there's no clean way for a language to avoid it without violating at least some of the behavioral guarantees that Java offers.Dareen
There's the more general (or, as you put it, more fundamental) Diamond Problem that involves ambiguity. The Diamond Problem is often called the Deadly Diamond of Death problem because people respond to sex and violence imagery, these are really different (if related) things. The Deadly Diamond of Death earned its name because of the effect of destructors (or, in cases languages, constructors) being being called multiple times during an object's normal lifecycle. Note that if Java had multiple inheritance, it could end up with a DDOD problem because Java constructors are not virtual.Enactment
@TedHopp: The constructor issue could be side-stepped if, when a class inherited multiple base classes, at all but one had to be declared as a "secondary base class" whose parent constructor calls might be bypassed. And I guess that could resolve some other ambiguities as well. Destructors may be the most spectacular thing that could fail as a result of the DDoD, but if one doesn't call diamond patterns that create ambiguity "deadly", what would one call them to distinguish them from diamonds that don't create any ambiguity?Dareen
I'd call them diamond problems. If there's no ambiguity, there's no problem.Enactment
B
-1

The Deadly Diamond of Death

The problem of deadly diamond of death arises when we have ambiguity regarding resolving a variable or a method in a class that derives from more than one classes and the two or more base classes have same name for the methods or variables compiler wouldn't be able to correctly resolve the method or the variable from their name.

  1. This is more of a design choice made by the makers of Java to avoid the complexities that languages like C++ ( which allow multiple inheritance ) have.
  2. Java creators could have provided some scope resolution operator and that would have solved this challenge ( albeit not completely)

Points to Consider:

  1. This problem arises due to the fact that instance variables and methods belong to the objects that create them not to the classes themselves.
  2. Static methods and variables can be accessed anywhere using the class name.
  3. When we declare the variables in a subclass with the same name as that in the superclass, it hides the inherited variables (Whether static or non-static) however, for methods the approach is different for static and non-static methods.

Coming back to the problem: diamond of death

here since we don't have scope resolution operator in Java and the instance variables belong to their instances and not classes, if the Cat was allowed to derive from the two classes above it, it would lead to ambiguity as the classes above it have methods and variables with same name and hence compiler will get confused which method to invoke when an object of Cat class is used to invoke any method.

class Animal {
String species;

void sleep() {
    System.out.println("Animal is sleeping");
}
}
class PetAnimals extends Animal {
String habitat = "Home";

@Override
void sleep() {
    System.out.println("PetAnimal sleeps in a home.");
}

void roam() {
    System.out.println("PetAnimal roams around the house.");
}
}
class WildAnimals extends Animal {
String habitat = "Forest";

@Override
void sleep() {
    System.out.println("WildAnimal sleeps in the forest.");
}

void roam() {
    System.out.println("WildAnimal roams in the wild.");
}
}
class Cat extends PetAnimals, WildAnimals {  // Java doesn't allow this!
// Problem: Which sleep() to call? From PetAnimals or WildAnimals?

void showHabitat() {
    System.out.println(habitat); // Which habitat to choose? "Home" or 
   "Forest"?
}
}
  public class MainTest {
  public static void main(String[] args) {
    Cat myCat = new Cat();
    myCat.sleep();  // Which sleep() should be invoked?
    myCat.showHabitat(); // Which habitat will be chosen?
}
}

How Does interface solve this:

  1. Variables inside an interface are public static as Interfaces can't be instantiated.
  2. User defined methods do not have any implementation and it only provides a contract that all the classes implementing this interface must provide their own implementation for these methods. It is indifferent to how these implementations achieve a desired task.

multiple inheritance from interface and class with same name

A class may inherit two or more fields with the same name, either from two interfaces or from its superclass and an interface. A compile-time error occurs on any attempt to refer to any ambiguously inherited field by its simple name. A qualified name or a field access expression that contains the keyword super (§15.11.2) may be used to access such fields unambiguously.

Therefore, since the interface variables are static they can be called using the interface name multiply inherited fields hence ambiguity gets resolved.

and for the Code:

// Base interface Animal
   interface Animal {
       void sleep();
   } 

 // PetAnimal interface extending Animal
 interface PetAnimal extends Animal {
    void roam();
 }

// WildAnimal interface extending Animal
  interface WildAnimal extends Animal {
      void roam();
  }

 // Cat class implementing both PetAnimal and WildAnimal
   class Cat implements PetAnimal, WildAnimal {
     @Override
     public void sleep() {
       System.out.println("Cat sleeps peacefully.");
     }

    @Override
    public void roam() {
        System.out.println("Cat roams like both a pet and a wild 
   animal.");
   }
   }

 public class MainTest {
    public static void main(String[] args) {
        Cat myCat = new Cat();
        myCat.sleep();    // No ambiguity: Cat provides its own sleep() method
        myCat.roam();     // No ambiguity: Cat provides its own roam() method
  }
}
Backup answered 25/8, 2024 at 9:9 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.