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.

  • cheong00 0

    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)

    • Collin Jasnoch 0

      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.

      • cheong00 0

        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”.

        • Nicholas Kinney 0

          Protected public static private tbh

      • Nicholas Kinney 0

        Did you read his comment? Private backers are encapsulated pieces of code and are not state. 

  • cheong00 0

    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.

  • Hzj_jie 何子杰 0

    “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.

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

      Exactly

  • Neil Walker 0

    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. 

    • Jeroen Haegebaert 0

      There’s no reason interfaces shouldn’t be able to evolve/change over time (i.e., versioned) without breaking users. 

      • Frode Nilsen 0

        Yes, by inheritance!

      • Wil Wilder Apaza Bustamante 0

        There’s no reasons to evolve interfaces as a language feature.

  • Xavier Poinas 0

    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?

    • Alfonso Ramos Gonzalez 0

      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.

      • Frode Nilsen 0

        And when it clash with extensions methods?

    • Jeroen Haegebaert 0

      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.

  • Rehan Saeed 0

    This is the one feature of C# 8 that I don’t like and I think is a mistake.

    • Mike-E 0

      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 0

        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.

        • Mike-E 0

          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 

        • Mike-E 0

          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.

        • Alfonso Ramos Gonzalez 0

          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?

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

      • Sam 0

        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. 

  • Charles Roddie 0

    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. )

  • gekk RK 0

    And how to solve diamond inheritance problem?

  • Mohamed Elshawaf 0

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

    • Heath StewartMicrosoft employee 0

      It’s the Crayon syntax highlighter plugin for WordPress.

      • Mohamed Elshawaf 0

        Thanks, I was looking for similar plugin for my blogger blog!

  • Yves Goergen 0

    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.

    • Matt Warren 0

      > 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.

      • Yves Goergen 0

        Thank you, that’s good to know.

Feedback usabilla icon