Default implementations in interfaces

Mads Torgersen

Mads

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

Mads Torgersen
Mads Torgersen

C# Lead Designer, .NET Team

Follow Mads   

61 comments

  • Avatar
    cheong00

    Does it mean we can now define private member in interfaces?
    That’s because as far as I understands, the default implementation would still required to use defined member of the interface only, and IMO in the most cases, useful default implementation would need access to some private members. (This is the primary reason why we choose base classes over interface when need to choose between them)

    • Avatar
      Collin Jasnoch

      The example given does not imply private members being allowed and shows an example of where it is used and prvate members are not needed. Your assumption is just wrong. While it may appear that in your case you need private members, that is likely the line. If you are storing state it should be stored in the class heirarchy.

      • Avatar
        cheong00

        No. I’m just arguing the usefulness of implementation like this, because similar effect has already been achievable with extension method.
        On the other hand, if there can be private member defined in inteface for this default implementation to interact with, there can be some really useful things be done.
        We all know that the current defination of interface does not allow defining private members, so I put another suggestion that instead of providing default implementation on the interface itself, why don’t we specify a default implementation base class that provides all the methods which we want to provide default implementation? Of course instead of private and protected, we may need new accessibility modifier for this kind of “private member”.

  • Avatar
    cheong00

    For some reason, I hope you can find it worth considering to allow interfaces to specify base class for default implementations. That base class could be abstract class that provides implementation for methods that it want to provide, and for members which the class wouldn’t provide default implmentation it can just specify them as abstract members. In this way we can somehow solve the “multiple base class” problem – either need to explicitly cast to interface when ambiguity is found, or find some way to define proper resolve order of interface.

  • Avatar
    Hzj_jie 何子杰

    “Oracle did this” is not a reasonable argument of doing the same thing in .net. I’d prefer to call it a horrible and easy-to-be-abused feature.

  • Neil Walker
    Neil Walker

    When you over engineer something it doesn’t get better, it starts to become a mess.

    There’s a reason why it’s an interface, if your want code, user an abstract class. 

    You’re re just trying to fix an edge case by ruining a simple principle. Just like java did with enums. 

  • Avatar
    Xavier Poinas

    This seems quite sloppy to me. Isn’t this what abstract classes are for?
    With those changes, what’s the difference between an interface and an abstract class?
    The only one I see is that a class can only inherit one (abstract) class but can implement several interfaces. The restriction on having only one base class was to avoid the typical issues associated with multiple inheritance. With interfaces behaving like classes aren’t we back to multiple inheritance?

    • Avatar
      Alfonso Ramos Gonzalez

      C# has multiple – interface – inheritance that is nothing new.

      I guess you are worried about the classic diamond problem. Well, today, without C# 8.0, you can have a class that implements multiple interfaces with members of the same name. You can have them separate simply by having them implemented explicitly.

      I suppose the source of this worry comes from C# obscuring the fact that the in CLR all interface member implementations are explicit (this is clean in VB.NET where you need the “implements” statement). With the interface default implementation that is not changing, they will be explicit.

      No new public members will be exposed by classes implementing them (unless the author of those classes changes the code to implement them), thus, these members will only be accesible after a cast to the interfaces (for example, simply by passing the object to a method that takes the interface instead of the class), and since you are accesing via the interface, there is no ambiguity.

      For a class that has not been modified to implement the new interface members that have a default implementation, they function like extension methods (after all, the default implementation is in terms of the other members of the interface). And thus, they do not pose any threat to the state of the class. And of course, the author can choose to provide an implementation for these members in a future version.

      As described in the article, this arrangement allows authors to extend interfaces without breaking client code.

    • Avatar
      Jeroen Haegebaert

      The only reason this feature exists is to be able to version interfaces (i.e., change them over time) without breaking users. It’s long overdue.

    • Avatar
      Michael DeMond

      Agreed… this is up there with the async/await disaster and I hope I never have to encounter (and certainly will never use).

      • Hugo Ferreira
        Hugo Ferreira

        I also don’t like this.
        An Interface is a contract.
        This is like a addendum to that contract.

        What is the problem with async/await ?
        I’m curious because I’m in a way of refactor a aplication that started before .NET 4.5 to use await/async.

        • Avatar
          Michael DeMond

          Haha… unfortunately, we are stuck with it and it is not an area of focus, nor does it look like it will be; we are too busy adding default implementations to interfaces instead.   While async/await it is an improvement from the previous model, a lot of questionable design considerations and conventions were applied to it that degrade development experience.  I’ve been keeping a nice collection of evidence in this vote here: https://visualstudio.uservoice.com/forums/121579-visual-studio-ide/suggestions/9126493-improve-asynchronous-programming-model 

        • Avatar
          Michael DeMond

          Sigh… this blog software.  I posted a reply to your question but it did not take.  I am not sure what’s more embarrassing, async/await, or the fact that MSFT — a technology giant — is using WordPress for its blogging implementation.

          Anyways, I have a list of grievances on this subject, along with a compilation of resources that demonstrate the inadequacies of the current design (to put it lightly) posted in another reply on this thread.

        • Avatar
          Alfonso Ramos Gonzalez

          I do not think that async/await is a disaster.However, I believe the argument comes from the fact that using an async method encourages to make the caller async, which can lead to async propagation. The fact that you have an async call somewhere down the line is an unexpected reason of change.I suggest a read of the article “What Color is Your Function?

        • Avatar
          Hr Universe

          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.
          With this feature SOLID principles are going to die and Abstract class will be inefficient….

      • Avatar
        Sam

        Async/await disaster? Man am I glad I don’t have to maintain your code.
        I highly suggest you read some tutorials online and learn how to use it properly. Async/await is probably the most powerful concept introduced to programming since object-oriented programming. It completely redefined the way asynchronous operations are written to make asynchronous programming nearly as easy to do as synchronous programming. 

  • Avatar
    Charles Roddie

    People worry that this will lead to clean code resulting from multiple inheritance. In that case it may be better to give a warning on creation of these interfaces, which can be disabled when writing Java interop code. (It is said that the real reason for this feature is Java interop. )

  • Avatar
    Mohamed Elshawaf

    Great to see this finally in C#! 
    Side question: does anyone know what JavaScript plugin is used for the code snippets in this post? 

  • Avatar
    Yves Goergen

    Does this require changes to the .NET assembly file format? I.e. will post-compilation tools have to be updated to support this feature? From my past experience working with APIs like Cecil, I don’t see how this feature would have been possible before.

    • Avatar
      Matt Warren

      > Does this require changes to the .NET assembly file format?I was fortunate to have a chance to chat with Mads about this exact question at a conference a while back. He explained to me that there’s no .NET assembly file format change, you’ve always been able to (in metadata) associate a function with an interface, it’s just that the runtime has then blocked this, by throwing an error when you load an interface in this scenario.So what’s happened now is that this restriction has been relaxed. Of course, there’s a lot of other work in the runtime to make it possible, but in terms of assembly file format, there’s not needed to be a change.(I hope that I’m remembering the conversation correctly!!)I guess that some tools will still have to be updated to recognise this scenario and do the right thing, i.e. show that there is a method associated with an interface.

  • Avatar
    Sam

    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.

  • Avatar
    Sergey Nosov

    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.

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

    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.

    • Avatar
      Hr Universe

      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
    Nicholas Kinney

     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…

  • Antony McKane
    Antony McKane

    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. 

  • Avatar
    jiaming hu

    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?

  • Avatar
    Maciej Pilichowski

    Without private methods in interface it has little or no use IMHO, because in this example extension would be sufficient. Pity it is the last major feature — I still wait for types unions and intersections 🙂

  • Avatar
    Ledenev Stanislav

    What a BS! Nice and beautiful interfaces becoming complete and utter crap. And motivation for this “change” is rather ugly too. I’d fire person (or group of persons) who “invented” this.
    UPD: Seems like mind twisted “experts” from C++ committee have joined .NET team.

  • Avatar
    johnny 7

    what a bunch of nonsense! turning simple things into java/c++/scala syntax crap. You need to stop messing arround with c#. put the VB team in charge and fire those who came up with this useless ideas. you where supposed to be the leaders…not the followers. 😤🤮

  • Avatar
    Sergii Kovalchuk

    Wow, that give us a chance to broke OCP! And we can use 3rd party classes in interfaces and create more vendor lock. We could even create an integration hell in unit testing with this powerful feature! Also, we could forgot about word ‘contract’ – this term means nothing after this powerful feature. Now we can write shitcode much more easily! Thanks!

  • Avatar
    Hr Universe

    I am very confused…
    They are really going to change a very basic and fundamental concept of OOP!!!!
    Why should an interface has default implementation for method?????
    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….

Leave a comment