When should we use default interface method in C#?
Asked Answered
L

2

17

In C# 8 and later, we have default interface methods, so:

Doesn't it ruin the principle of interface?

When should we use default interface methods instead of base (abstract) class?

Limp answered 10/7, 2020 at 11:7 Comment(4)
The idea behind default interface methods is extensibility. Consider you already have a codebase. Now a new feature request requires one of your interfaces to include a new method. Without default interface methods, you'd have a hard time. Now, you can add the the new method, implement it where it needs to and still have the preexisting code still work without changes.Bendick
This question is difficult, if not impossible, to answer here on Stack Overflow because it will be based on opinions. You ask if it is a good idea, you ask if it would be a better idea to do something else. It would be better if you first checked if the questions and answers here on SO already cover your question, and if not, rewrite it to be less based on opinions.Pelag
This has been asked (for Java, not C#, but the principle is practically identical) on Software Engineering and has a few relatively detailed answers (theoretical/design questions like this are probably a better fit for SE in general.) There are also numerous articles that answer this question, i.e. Red Hat's blog, which, similarly to @Fildor's comment, states that "[they] provide a way to extend interfaces ... without breaking previous implementers"Misinterpret
If you check the correct tag's description you'll find an explanation and examples. No, it doesn't ruin interfaces, it's not similar to base classes. DIMs are meant for versioning, traits, and interoperability with platforms that already use default methods, like the Android SDKRipon
S
28

Why do we have interfaces?

From a theoretical point of view, both interface implementation and class inheritance solve the same problem: They allow you to define a subtype relationship between types.

So why do we have both in C#? Why do we need interfaces at all? Can't we just define an interface as an abstract class, just as we do, for example, in C++?

The reason for this is the diamond problem: (Image source)

enter image description here

If both B and C implement A.DoSomething() differently, which implementation should D inherit? That's a hard problem, and the Java as well as the C# designers decided to avoid it by allowing multiple inheritance only for special base types which do not include any implementation. They decided to call these special base types interfaces.

So, there is no "principle of interface". Interfaces are just a "tool" to solve a particular problem.

So why do we need default implementations?

Backwards compatibility. You wrote a vastly successful library used by thousands of developers worldwide. Your library contains some interface I, and now you decide that you need an extra method M on it. The problem is:

  • You can't add another method M to I, because that would break existing classes implementing I (because they don't implement M), and
  • you can't change I to an abstract base class, because that, as well, would break existing classes implementing I, and you will lose the ability to do multiple inheritance.

So how do default implementations avoid the diamond problem?

By not inheriting those default methods (example inspired by the one in this article, see the full article for some interesting corner cases):

interface I1
{
    void M() { Console.WriteLine("I1.M"); } // default method
}

interface I2
{
    void M() { Console.WriteLine("I2.M"); } // default method
}

class C : I1, I2 { }

class Program
{
    static void Main(string[] args)
    {
        // c, i1 and i2 reference the same object
        C c = new C();
        I1 i1 = c;
        I2 i2 = c;

        i1.M(); // prints "I1.M"
        i2.M(); // prints "I2.M"
        c.M();  // compile error: class 'C' does not contain a member 'M'
    }
}

Can't I just use extension methods instead of default interface methods?

Default interface methods are not inherited, but they are still virtual. Now, what does that mean? It means that a class can override the behavior of a default interface method:

interface I
{
    void M() { Console.WriteLine("I.M"); } // default method
}

class C1 : I { }

class C2 : I
{
    void I.M() { Console.WriteLine("C2.M"); }
}

class Program
{
    static void Main(string[] args)
    {
        I i1 = new C1();
        I i2 = new C2();

        i1.M(); // prints "I.M"
        i2.M(); // prints "C2.M"
    }
}

You cannot do that with extension methods.

Shlomo answered 10/7, 2020 at 11:49 Comment(2)
One of the most lucid, simple / clear explanations I have ever read.Brute
@Shlomo Starting with the diamond problem made the answer more interesting to follow, thanks for spending time to write such a comprehensive answer.Limp
G
5

As it is explained in the documentation, there are two primary applications:

Extending existing APIs

Virtual extension methods enable an API author to add methods to an interface in future versions without breaking source or binary compatibility with existing implementations of that interface.

It is thus intended as a means to extend APIs (= a set of interfaces) without having to update all existing implementations (since they need to implement the newly added functions).

The traits pattern

The traits pattern allows to extend a class with multiple sets of pre-implemented methods. This is not possible with abstract classes: A given class can only inherit from a single parent class, but from multiple interfaces.

Note that this feature comes with the diamond inheritance problem. Thus, apart from these specific applications, this feature should not be used to replace abstract classes.

Grecoroman answered 10/7, 2020 at 11:21 Comment(1)
DIMs don't have the diamond inheritance problem any more than plain interfaces do. With plain interfaces, explicit interface implementation avoids the problem. DIMs are invoked the same way as explicitly implemented interfacesRipon

© 2022 - 2024 — McMap. All rights reserved.