C# 8: Default Interface Methods Implementation

Continuing to examine new C# 8 features, today we are taking a look at a bit controversial one. It’s a possibility to provide default interface methods implementation.

How will this possibility change the way we write C#? Why is it being introduced? I’ll try to address these questions today 🙂

Interfaces today

As we all know from the current version of C#, interfaces allow to define a kind of contract, which must be respected by a class implementing it. Today interfaces can only contain definitions of methods (with no body). These methods are then actually implemented by concrete classes. If a class doesn’t implement all of its interface’s methods, compiler produces an error.

What’s problematic in this approach? Assuming that you have the following interface and class(es) implementing it:

interface IDeveloper
{
void LearnNewLanguage(string language, DateTime dueDate);
}
class BackendDev : IDeveloper
{
public void LearnNewLanguage(string language, DateTime dueDate)
{
// Learning new language…
}
}

With time, you may want to extend IDeveloper interface by adding a new method, for instance:

interface IDeveloper
{
void LearnNewLanguage(string language, DateTime dueDate);
void LearnNewLanguage(string language); // new method added
}

Now you have a problem, because the new method must be implemented in all places where the interface was used. Compiler gives you an error as long as it’s not done:

C# 8: Default Interface Methods Implementation: C# compilation error - interface member not implemented
C# compilation error – interface member not implemented

If your interface is used in many places, also by another teams or developers (which is often the case in reality), this is a breaking change 🙁

It may be really painful, depending on how extensively your interface is used. In any case, all classes based on the IDeveloper interface must implement the new LearnNewLanguage(string language) method. Only then the code compiles.

One of the reasons for introducing into C# default interface methods is to avoid such breaking changes scenarios 🙂

Default Interface Methods

As we can read in the feature’s design notes, an inspiration for it is a similar concept already alive in Java – Default Methods.

The main idea of this new C# feature is a possibility to provide a default implementation of an interface’s method.

Realization in C# 8.0

In our example using C# 8.0 we’ll be able to implement it as follows:

interface IDeveloper
{
void LearnNewLanguage(string language, DateTime dueDate);
void LearnNewLanguage(string language)
{
// default implementation
LearnNewLanguage(language, DateTime.Now.AddMonths(6));
}
}

In that case, our class implementing the IDeveloper interface can legally not implement this new method and there will be no compilation error:

interface IDeveloper
{
void LearnNewLanguage(string language, DateTime dueDate);
void LearnNewLanguage(string language)
{
// default implementation
LearnNewLanguage(language, DateTime.Now.AddMonths(6));
}
}
class BackendDev : IDeveloper // compiles OK
{
public void LearnNewLanguage(string language, DateTime dueDate)
{
// Learning new language…
}
}
class Program
{
static void Main(string[] args)
{
IDeveloper dev = new BackendDev();
dev.LearnNewLanguage("Rust"); // OK – default implementation of
// IDeveloper.LearnNewLanguage(string language) is called
}
}

Notice that it only works when BackendDev is contextually treated as IDeveloper. It means that a class doesn’t inherit members from the interfaces it implements:

BackendDev dev = new BackendDev();
dev.LearnNewLanguage("Rust"); // compilation error: class 'BackendDev'
// does not contain a member 'LearnNewLanguage'

What about multiple inheritance?

As some of you probably realized, this new feature exposes C# to a multiple inheritance problem (also known as Diamond of Death). So far C# didn’t have this issue, because we can only inherit from a single class. We can implement multiple interfaces, but so far the interfaces couldn’t provide methods’ implementation. Because of that, there was no Diamond of Death possible. Soon it’s gonna change 🙂

Diamond of Death in C# 8

In case of C# default interface methods we may illustrate this issue with the following code:

interface IDeveloper
{
void LearnNewLanguage(string language)
{
Console.Write($"Learning {language} in a default way.");
}
}
interface IBackendDev : IDeveloper
{
void LearnNewLanguage(string language)
{
Console.Write($"Learning {language} in a backend way.");
}
}
interface IFrontendDev : IDeveloper
{
void LearnNewLanguage(string language)
{
Console.Write($"Learning {language} in a frontend way.");
}
}
interface IFullStackDev : IBackendDev, IFrontendDev { } // uses default implementation,
// of LearnNewLanguage, but which one?
class Dev : IFullStackDev { }
class Program
{
static void Main(string[] args)
{
IFullStackDev dev = new Dev();
dev.LearnNewLanguage("TypeScript"); // which method is called? The one
// from IBackendDev or IFrontendDev?
}
}

Please note that the syntax or places in which compiler generates errors may still change in the final feature’s version.

To better illustrate this Diamond of Death example, take a look at the following diagram:

C# 8: Default Interface Methods Implementation: Diamond of Death example illustration
Diamond of Death example illustration

The question is: which method should be called in such case?

Solution: most specific override rule

C# 8.0 will solve this issue by introducing the most specific override rule. It means that in our case illustrated above, the compiler will issue an error and won’t let us do this.

To avoid this ambiguity, we’ll be forced to implement or override LearnNewLanguage(string language) in IFullStackDev interface. Only then it will be considered the most specific version of the method in the interfaces hierarchy we have. It will then be used when calling the method on objects contextually treated as instances of IFullStackDev. We could also implement it directly in the Dev class and use the class (not interface) type. It would then call the most specific method from the class. This way multiple inheritance issue will be eliminated.

Compiler for the rescue

There are a lot of other potential ambiguity scenarios that may take place after introducing into C# default interface methods. You can check all of them with potential solutions well-discussed on GitHub.

The general assumption is that all code which may lead to issues related to default interface methods implementations is detected by the compiler. In effect, we should get appropriate errors when compiling the source code. That way, programmer can fix all potential conflicts directly when these arise.

What about .NET Framework?

What’s interesting with default interface methods is that it requres changes in the runtime. According to current assumptions, it means that this feature will not work with .NET Framework! Only CoreCLR and Mono stack runtimes are going to receive these new updates.

Summary

As the motivation for introducing into C# default interface methods the language team members mention possibility to interact with some Android and iOS APIs, which already support such feature. They also claim that C# will get the traits programming language feature with default interface methods.

In my opinion this is the most controversial from all C# 8.0 new features. It completely changes something which was obviousness for the developers for years. Probably we’ll see less breaking changes issues when the interfaces are extended, but looking on the list of issues and edge cases it produces… Maybe assuming it already works in a similar way in Java we should just accept it? 🤔

Another interesting, .NET-specific aspect is that this feature will not work with .NET Framework. It’s probably the very first moment when the difference in pace between .NET Core and Framework is so explicit.

I’m also very curious about the performance implications of default interface methods. I’ll for sure be following this issue on GitHub to see how it evolves 🙂

What do you think? Is it a good idea to introduce default interface methods into C#?

.NET full stack web developer & digital nomad
0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments