Default implementations in interfaces

Mads Torgersen

Default implementations in interfaces

With last week’s posts Announcing .NET Core 3.0 Preview 5 and Visual Studio 2019 version 16.1 Preview 3, the last major feature of C# 8.0 is now available in preview.

A big impediment to software evolution has been the fact that you couldn’t add new members to a public interface. You would break existing implementers of the interface; after all they would have no implementation for the new member!

Default implementations help with that. An interface member can now be specified with a code body, and if an implementing class or struct does not provide an implementation of that member, no error occurs. Instead, the default implementation is used.

Let’s say that we offer the following interface:

interface ILogger
{
    void Log(LogLevel level, string message);
}

An existing class, maybe in a different code base with different owners, implements ILogger:

class ConsoleLogger : ILogger
{
    public void Log(LogLevel level, string message) { ... }
}

Now we want to add another overload of the Log method to the interface. We can do that without breaking the existing implementation by providing a default implementation – a method body:

interface ILogger
{
    void Log(LogLevel level, string message);
    void Log(Exception ex) => Log(LogLevel.Error, ex.ToString());
}

The ConsoleLogger still satisfies the contract provided by the interface: if it is converted to the interface and the new Log method is called it will work just fine: the interface’s default implementation is just called:

public static void LogException(ConsoleLogger logger, Exception ex)
{
    ILogger ilogger = logger; // Converting to interface
    ilogger.Log(ex);          // Calling new Log overload
}

Of course an implementing class that does know about the new member is free to implement it in its own way. In that case, the default implementation is just ignored.

The best way to get acquainted with default implementations is the Tutorial: Update interfaces with default interface members in C# 8 on Microsoft Docs.

Happy hacking!

Mads

65 comments

Discussion is closed. Login to edit/delete existing comments.

  • Michel Renaud 0

    My first impression is that nothing good can come out of this feature.

    • Sam 0

      Good thing the C# language design team thinks more deeply about things than “first impressions”.

  • Sam 0

    Thanks for the blog post, Mads. Can I suggest that you make it a little more meaty and talk about inheritance and such? I’ve read all the design notes, but most people don’t.

  • Sergey Nosov 0

    Relax everybody, it is not too bad. There is actually no inheritance happening when a class implements an interface.
    I, personally, would love me some multiple inheritance in C#, but this is not it.
    Think of this like of explicit interface implementations. Some consider explicit interface implementations hacky as it is; so it just adds to the hackiness in the same direction.

    • Sergey Nosov 0

      Hey, where did my paragraph breaks go?

  • Ladislav Burkovsky 0

    I wish we had extend everything “feature” instead.

  • Иван Архипов 0

    I very much hope that this will never happen. The most important task of interfaces is to declare their behavior by design. And now it turns out that there is both a default implementation and an implementation that can be changed in the interface implementation. It turns out the bomb.

    • Hr Universe 0

      They are really going to change a very basic and fundamental concept of OOP!!!!
      In OOP an interface is a contract for class that assigns structure of it.
      In fact because of this reason that interface doesn’t have implementation, classes can implement(inherit) from multiple interfaces.
      This is very mess….
      With this feature SOLID principles are going to die and Abstract class will be inefficient….

  • Nicholas Kinney 0

     I will try my hardest to be positive here. I’ve spent the last 15 years realizing that separation of concerns and polymorphism and encapsulation and abstraction is more important than you. You are wrong, sir. But I have an open mind and would love to see how late binding contracts without implementing would improve software and improve readability. Lambda is a powerful feature but you are taking inversion of control and spawning a new version of DLL hell without even knowing it. So much for SOLID principles to say the least. Don’t know how to dispose a object, no problem our object methods are static and singletons will live in infamy by our triple locking helix magic sauce in C#11!!!!!!! Lol…

  • Matthew Adams 0

    This change essentially enables you to use trait-based development.  Nice.

    • Olivier Jacot-Descombes 0

      This is a very important point I’m looking forward to. Traits allow the composition of classes easily without requiring (true) multiple inheritance. Traits support the Composition over inheritance principle.
      See the paper Traits: Composable Units of Behavior

  • Antony McKane 0

    This is just plain horrible.  It pointlessly blurs the line between interface and abstract base classes.  Keep interfaces as simple contracts of functionality and override functionality via derived classes. 

    • Hr Universe 0

      It’s a bad mistake….
      SOLID principle is going to die

  • jiaming hu 0

    I have a question about c# grammar, can I try to give feedback? But I can’t find a website about the discussion. Let me talk about it directly here?
    if (name == null){    throw new ArgumentNullException(nameof(name));}
    // Can you develop a grammar like this?name ?? throw new ArgumentNullException(nameof(name));

    There may be thousands of such judgments in the project, and then an exception is thrown. Can it be extracted into a single code to do it?

    • Steve 0

      Absolutely.
      You can do it with discard.

      _ = this.name ?? throw new ArgumentNullException(nameof(name));

  • Andrea Rossini 0

    Multiple inheritance? Is it you?

    • Steve 0

      Don’t think so.
      An interface does not has the ability to maintain states (fields), it can only define behaviors. It’s different from a class.

Feedback usabilla icon