Wednesday, September 25, 2019

C# 8 Interfaces: Dangerous Assumptions in Default Implementation

In taking a closer look at C# 8 interfaces, we need to consider that we can make things worse with default implementation.
Making assumptions with default implementation can lead to broken code, runtime exceptions, and slow performance.
One of the features that is being promoted about C# 8 interfaces is that we can add members to an interface without breaking existing implementers. But we can cause a lot of pain if we aren't careful. Let's look at some code that makes bad assumptions so that we can understand the importance of avoiding these problems.

The code for this article is available on GitHub: jeremybytes/interfaces-in-csharp-8, specifically the DangerousAssumptions project.

Note: this article uses C# 8 features, which are currently only implemented in .NET Core 3.0. For these samples, I used Visual Studio 16.3.0 and .NET Core 3.0.100.

Assuming Implementation Details
The main reason I am calling this out is because of a blog article that promotes code that makes really bad assumptions about implementation. (I'm not calling out the specific article because I don't want that blogger to get hammered with comments; I'm going to contact them discretely.)

The article in question is about how good default implementation is because we can add to interfaces after there are existing implementers. However, the code makes some bad assumptions. (This code is in the BadInterface folder of the GitHub project.)

Here is the original interface:


The article continues by showing an implementation of the interface "MyFile" (in the MyFile.cs file):


The article then shows that we can add a "Rename" method with a default implementation that won't break the existing "MyFile" class.

Here is the updated interface (from the IFileHandler.cs file):


MyFile still works so everything's great, right? Not exactly.

Bad Assumptions
The main problem with the "Rename" method is that it makes a *HUGE* assumption: the implementations are using a physical file on the file system.

Let's take a look at an implementation that I created to use an in-memory file system. (Note: this is my code; it is not from the original article. You can see the full implementation in the MemoryStringFileHandler.cs file.)


This class implements a naive file system that uses an in-memory Dictionary to hold text files. There is nothing here that touches the physical file system, and it does not reference System.IO at all.

Broken Implementer
With the update to the interface, this class is now broken.

If client code calls the "Rename" method, it will generate a runtime error (or worse, it will actually rename a file on the file system).

Even if our implementation is using physical files, it may be using files that are located in cloud storage and are not accessible through System.IO.File.

This is also a potential problem when it comes to unit testing. If a fake or mock object is not updated, but the code under test is updated, this will try to touch the file system when the unit tests are run.
Because a bad assumption is made in the interface, implementers of the interface are broken.
Unreasonable Fear?
It's pretty easy to think about this as an unreasonable fear. When I talk about mis-use of code, often the response is "well, that's bad programming." I don't disagree with that.

My general response is to wait and see how things are used. For example, I had a fear that "static using" would be abused. So far, I haven't seen that. But in this instance, there is at least one article out there that is promoting this type of code (and there may be more).

We need to be aware that these ideas are out there so that we can help people move back onto a happier path that won't cause as much pain.

As always, we get better by helping each other out.

Performance Issues
I started thinking about other ways that we could get into trouble when we make assumptions about interface implementers.

The previous example calls code that is outside of the interface itself (specifically, from System.IO). We can probably agree that doing something like that is a danger sign. But if we're using things that are already part of the interface, we should be okay, right?

Not necessarily.

Just as a quick example, I created an "IReader" interface. (This is more thought out than the embarrassing IReader interface that included a "Save" method in a previous article.)

Original Interface & Implementation
Here is the original IReader interface (from the IReader.cs file -- although the file has updates):


This is a generic interface with a method to get a read-only collection of items.

One implementation of this interface generates a Fibonacci Sequence (Yes, I have an unhealthy interest in generating Fibonacci Sequences.) Here is a FibonacciReader (from the FibonacciReader.cs file -- this file also has updates on GitHub):


The FibonacciSequence class is an implementation of IEnumerable<int> (from the FibonacciSequence.cs file). It uses an 32-bit integer as a data-type, so it overflows pretty quickly.


If you're interested in this implementation, take a look at TDDing into a Fibonacci Sequence in C#.

The DangerousAssumptions project is a console application that writes out the results of the FibonacciReader (from the Program.cs file):


And here's the output:


Updated Interface
So, we have working code. But at some point we might want to get an individual item from the IReader rather than getting the entire collection of items. Since we are using a generic type on the interface, and we do not have a natural ID property on the object, we'll pull out an item at a specific index.

Here's our interface with the "GetItemAt" method added (from the final IReader.cs file):


The "GetItemAt" includes a default implementation. At first glance, this doesn't look too bad. It uses an existing member of the interface (GetItems), so it is not making external assumptions. And it uses a LINQ method on the results. I'm a big fan of LINQ, and this code looks reasonable.

Differences in Performance
Since the default implementation calls "GetItems", it requires that the entire collection be returned before a specific item is picked out.

In the case of the FibonacciReader, this means that all of the values are generated. An update to the Program.cs file will show this:


This calls "GetItemAt". Here is the output:


If we set a breakpoint inside the FibonacciSequence.cs file, we can see that the entire sequence is generated for this.


Running the program will hit this breakpoint twice: once for the "GetItems" call and again for the "GetItemAt" call.

Performance Hindering Assumption
The biggest problem with this method is that it requires the entire collection of items to be retrieved. If this "IReader" is going against a database, then all of the items are pulled back so that a single item can be selected. It would be much better to let the database handle this functionality.

With our FibonacciReader, we are calculating each new item. This means that the entire list needs to be calculated in order to pull out the one item that we want. Calculating a Fibonacci sequence is not very CPU-intensive, but what if we were doing something a bit more intensive, like calculating prime numbers.

You might be saying, "Well, there's a 'GetItems' method that returns everything. If that takes so long to do, then it probably shouldn't be there." And that's a fair statement.

But the calling code doesn't know about any of this. If I'm calling "GetItems", I know that I'm going through a (possibly) network and data-intensive process. If I'm asking for a single item, I don't necessarily think that same thing.

Specific Performance Fix
For the FibonacciReader, we can put in our own implementation to get much better performance (in the final FibonacciReader.cs file):


The "GetItemAt" method overrides the default implementation that is provided in the interface.

This uses the same "ElementAt" LINQ method that the default implementation uses. But instead of using that method on the read-only collection that comes back from "GetItems", it uses it on the underlying FibonacciSequence, which is an IEnumerable.

Since the FibonacciSequence is an IEnumerable, calling ElementAt will stop once it gets to the selected item. So rather than generating the entire collection, it only generates items up to that specific index.

To try this out, keep the same breakpoint as above and run the application again. This time, it will only hit the breakpoint once (for the "GetItems" call). It does not hit the breakpoint during the "GetItemAt" call.

A Bit Artificial
This example is a bit artificial because we don't normally pick items out of a dataset by index. But we could think of something similar that would happen if we had a natural ID property.

If we pulled items out by ID rather than index, we could have the same performance issues on a default implementation. The default implementation would require all items to be returned to pick out just one. Letting a database or other "reader" pull out an individual item by ID would be much more efficient.

Think About Your Assumptions
We always make assumptions. If we tried to code for every possible use of our libraries, we would never be done. But we need to think about the assumptions that we do make for our code.

This doesn't necessarily mean that the "GetElementAt" default implementation is a bad one. It does have potential performance issues. But if the data sets are small or the calculated elements are "cheap", then it may be worth the trade.

I'm still not a big fan of changing an interface after it has existing implementers. But I understand that there are scenarios where it is preferable to other options. Programming is all about problem solving, and that includes weighing pros and cons for each tool and technique that we use.

Default implementation has the potential to cause harm to the implementers of the interfaces (and potentially the callers of those implementations). We need to take special care regarding our assumptions when it comes to default implementation.

Happy Coding!

Tuesday, September 24, 2019

C# 8 Interfaces: Properties and Default Implementation

In taking a closer look at C# interfaces, we'll start by exploring default implementation and how it relates to properties. Here's what I've found:
Default implementation is really good for calculated properties; it's not so good for read/write properties.
The code for this article is available on GitHub: jeremybytes/interfaces-in-csharp-8, specifically the InterfaceProperties project.

Note: this article uses C# 8 features, which are currently only implemented in .NET Core 3.0. For these samples, I used Visual Studio 16.3.0 and .NET Core 3.0.100.

Default Get
Let's start by looking at an interface that has a default "get" for a property. Here's an interface that describes a regular polygon and has a default implementation (from the IRegularPolygon.cs file):


This describes a regular polygon -- a geometric shape with 3 or more sides where each side is the same length.

The interface describes four properties. (1) NumberOfSides is a read-only property that tells how many sides the shape has. This is read-only because we do not want type of shape (triangle, square, etc.) to change after it is created.

(2) SideLength is a read/write property. The size of the shape is allowed to change during its lifetime.

(3) Perimeter is the distance around the shape. This is a calculated property. Since the calculation is the same for every shape, we included a default implementation.

This code uses the expression-bodied member syntax to return the number of sides multiplied by the side length. If you're not familiar with expression-bodied members, this is the equivalent of the following code:


The expression-bodied member syntax is a short-hand that removes the braces and the "return" keyword. I'll be using the shorter syntax throughout this article, but they are equivalent in functionality. Read more here: Expression-bodied members - Properties.

(4) Area is the space inside the shape. This is also a calculated property, but the calculation is different from each shape. Because of this, we do not provide a default implementation. It will be up to each class to specify it's own calculation.

A Shorter Default Get
There is a slightly shorter way to specify a default "get" for a property (from the IRegularPolygon.cs file):


This is a shorter version of the expression-bodied member syntax that can be used with read-only properties. In this case, we can get rid of the "get" keyword and the braces around that.

This syntax makes it a bit harder to tell whether this is a property or a method. (The difference is that an expression-bodied method would have empty parentheses after "Perimeter".) Read more here: Expression-bodied members - Read-only properties.

Implementing the Interface
Here is a square that implements this interface (in the SquareFromInterface.cs file):


This class implements the IRegularPolygon interface. It provides automatic properties for NumberOfSides and SideLength, and it has a constructor that initializes those properties. There is also an implementation for the Area property. This uses the same expression-bodied member syntax shown above.

One thing to note is that the Perimeter property is not implemented in this class. It relies on the default implementation provided by the interface.

Using the Class
This project is a console application, and we use this square class in the Program.cs file.


This code creates 2 instances of the SquareFromInterface class and displays the properties to the console. The output is unsurprising:


An important thing to note about this code is that accessing the "Perimeter" property from the ShowInterfacePolygon method works. Since the parameter (polygon) is IRegularPolygon, it uses the default implementation for Perimeter.

The Property is on the Interface Only
In this case, the concrete type, SquareFromInterface, does not have a Perimeter property. The property exists only as part of the interface. We can see this if we try to change the type of the "polygon" parameter to our concrete type:


In this code, the parameter is "SquareFromInterface". This type does not explicitly have the Perimeter property, so the code fails to build. (We can see the red squigglies under "Perimeter" in the code sample above.)

Overriding the Default Implementation
If we wanted to, the SquareFromInterface class could provide its own implementation of Perimeter. If it did provide that implementation, then that is the value that would be used, even if we cast the type to the interface. We'll take a closer look at how this works in a later article when we look at default implementation for methods.

Default Implementation for Read/Write Properties
There are some restrictions on default implementation for properties. When we have both a getter and a setter, we must provide implementations for both get/set or neither.

These examples are not valid (from the IBadInterface.cs file):


The first property has a default implementation for the get, but an abstract set (meaning, the implementing class needs to provide that). This is not allowed.

The second property has an abstract get with default implementation for the set. (The default implementation happens to be an empty method.) This is also not allowed.

For read/write properties, we need to provide default implementation for both get and set or for neither.

Note: when we provide default implementation for neither get nor set, we just end up with a regular abstract interface property like "SideLength" above.

Default Implementation for Set
Now that we've talked a little about read/write properties, the next question is whether default implementation makes sense for a read/write property, specifically how do we come up with a default implementation for "set".

No Automatic Implementation
Something to think about: there is no way for us to create an automatically implemented property (or auto property) as a default implementation. Let's look at this more closely. Here is the code from the SquareFromInterface class that we saw above:


Both NumberOfSides and SideLength are auto properties, meaning the compiler fills in some gaps for us. For example, the SideLength property really means this:


This is a property with a backing field. Since the "get" simply reads the backing field, and the "set" simply sets the backing field, this can be shortened to the auto property syntax that we have above. (As a side note, that is why the field is grayed-out; Visual Studio is telling us we can make this an auto property.)

The problem with automatic properties is that they use a backing field. This is instance data on the class. Interfaces are not allowed to have any instance data, so we cannot have backing fields in the interfaces.

This means that we can *not* create a property in an interface with an implementation that is an automatic property.

What Can We Put in the Setter?
The next question is whether there is anything that we can put into a default setter that would make sense. I'm not sure there is. (If you have any ideas, be sure to share them in the comments.)

Based on auto property syntax, it's tempting to try something like this for the setter (from the IBadInterface.cs file):


Unfortunately, this code compiles. It's tempting because it feels like we can cheat the auto property syntax for the setter. But in reality, it creates a Stack Overflow.

To show this, we implement this bad interface in an empty class (from the BadObject.cs file):


Since this object has no members, it uses the default implementation from the interface.

Here is some code to use that object (from the Program.cs file):


We can create the object with no problems. But if we try to set the BadMember property, bad things happen, specifically we get a Stack Overflow:



This isn't a surprise. When we set the "BadMember" property, it calls the setter which takes the value and uses it to set the "BadMember" property, which calls the setter for the "BadMember" property... You can see the problem.

Now this problem isn't any different from code that isn't using default implementation. If we create a property setter like this in a class, we will get the same Stack Overflow exception. The difference is that it's a bit more tempting to try something like that with default implementation in the interface to try to mimic what we would get from an automatic property.

Do Setters Make Sense?
Based on the fun that we've had here, I've wondered if there is a scenario where a default implementation for a property setter would make sense. So far, I haven't come across one. Be sure to share you ideas of you've got them.

Greenfield Abstract Class
If I was implementing the regular polygon scenario in a greenfield application (meaning, brand-new code), then I would probably use an abstract class. The implementation for the "Perimeter" calculated property would be just the same. But we could get some more safety for the NumberOfSides and SideLength properties.

Just to show the differences, I coded up the same functionality as an abstract class (from the AbstractRegularPolygon.cs file). First the NumberOfSides property:


The setter in this property has a guard clause to make sure that there are at least 3 sides to our polygon.

The SideLength property has a similar guard clause to make sure the length is greater than zero:


The rest of the class has a constructor to set the properties, and declarations for Perimeter and Area that look very similar to the interface:


The main difference is that for the abstract class, we mark Area as "abstract". We don't have to mark Area as "abstract" in the interface because that is the default.

Another Square Implementation
In the sample, we have a square class that inherits from the abstract class (from the SqureFromAbstractClass.cs file):


This class is a bit shorter than the one that implemented the interface. That's because it does not need to provide implementations for NumberOfSides or SideLength -- these come from the base class. The constructor calls the base class constructor with a hard-coded "4" for the number of sides.

Then we have an override of the Area property. This looks the same as our other square class.

Using the Square
The console application has code to use SquareFromAbstractClass (in the Program.cs file):


This code creates 2 instances from the interface class and 2 instances from the abstract class class. There is a different display function for the abstract class:


This is almost the same as the code that displays the interface properties. The only difference is the parameter type.

And we get similar output:


Since the display functions are so similar, it would be nice to combine them. In other samples, I've used "dynamic" to create a shareable method. But I ran into some problems when I tried that here.

Issues with Dynamic and Default Implementation
The regular polygon code is taken from a sample I use when teaching interfaces. For that code, I use a single method that can display multiple unrelated types. (The code is on GitHub if you're interested: DisplayPolygon sample.)

I ran into a problem when I tried that with the code that we have here. Here is a shareable method (from the Program.cs file):


This uses a "dynamic" as a parameter. This means that it is resolved at runtime rather than compile time. The good thing about this is that it will work with any object. And as long as the property or method is available on the object at runtime, everything works fine.

Or it almost works in this case.

Here's the code that calls the method:


But when using the dynamic method with the default property implementation, we get a runtime exception:


This is telling us that the runtime binder cannot find the "Perimeter" property on the "SquareFromInterface" object.

This is true. The "SquareFromInterface" class does not have its own "Perimeter" property. Instead, it relies on the default implementation from the interface.

You might be thinking that we need to pass to cast the object to the interface type before we pass it to the method. Well, it turns out that we did do that:


The "largeSquare" variable that we use is an IRegularPolygon (our interface). But even though we pass that type through, the runtime binder picks up the concrete object.

I don't know if this is a problem with the runtime binder, or whether this is intentional. I'll just leave a warning that when relying on a default implementation of an interface, there may be problems when combining it with "dynamic" objects.

Just as a note: the "dynamic" method works just fine with the abstract class class since "Perimeter" is part of the base class.

Update: I explored this behavior a bit further: C# 8 Interfaces: "dynamic" and Default Implementation.

Wrap Up
There has been a lot to think about. Default implementation seems like it can be really useful for calculated properties, particularly if we need to add a property after the interface is in a production environment.

But when it comes to setters for properties, default implementation doesn't seem to make much sense. And it's easy to get a stack overflow if we include a self-reference in the implementation.

As a reminder, you can get the code (and additional article links) from the GitHub repo: jeremybytes/interfaces-in-csharp-8.

We have a good idea of what the mechanics are for default implementation for properties. In future articles, we'll look at some guidance on default implementation in general.

Happy Coding!

Monday, September 23, 2019

A Closer Look at C# 8 Interfaces

There are a lot of changes to interfaces in C# 8 -- not just default implementation. Last time, I had a bit of a rant about those changes. Now it's time to settle down and take a closer look at what those changes are and better understand them.

The short list of changes includes the following:
  • Default implementation
  • Access modifiers
  • Static members
And there are a lot of smaller things that come up once we start looking at these features.

This is too much to talk about in one article, so the next several articles will be looking at these items more closely. I've been looking at the preview versions of .NET Core 3.0 (the first environment to support these features). Now that .NET Core 3.0 has been released, we can dive into code to see what is there, what is possible, what the compiler allows, and what the runtime allows.

Update: If you would like a video walkthrough with lots of code, take a look at this talk from the Phoenix-area user groups: https://www.youtube.com/watch?v=on-MIseN6gU (recordded 24 June 2020).

Default Implementation
Default implementation allows us to add implementation code to our interfaces. This means that we can provide method bodies for interface methods, events, indexers, and properties.

In looking at default implementation, there are a few questions that we will try to answer.

Property Get / Set
There are some things to explore about properties. For example, can you provide a default for a getter or setter separately, meaning a default implementation for a getter with an abstract setter? (The short answer is no.)

Update - Article now available: C# 8 Interfaces: Properties and Default Implementation.

Property Setter?
Since interfaces do not have any instance members (such as backing fields for properties), does it make sense to provide a default implementation for a setter? Is there a useful setter that we can provide?

Update - Article now available: C# 8 Interfaces: Properties and Default Implementation.

Generic Implementations
Would it be useful to create an interface that *only* has members with default implementation? If they have generic type parameters, this may be a way to add functionality to classes by only noting the interface and not changing the class itself.

Guidelines for Defaults
I've already seen an article with a really bad example of default implementation. The example makes assumptions about the concrete types that will be used and creates a scenario that would break implementations and make unit testing difficult.

Based on this, we need to take a look at what we put into default implementations to make sure that we keep a good environment for the folks using our interfaces.

Update - Article now available: C# 8 Interfaces: Dangerous Assumptions in Default Implementation.

Unit Testing
Now that we have code in our interfaces, how do we test it appropriately? On the surface, it seems like we can create a mock object and go. But some interesting things may pop up once we start looking at this more closely.

Update - Article now available: C# 8 Interfaces: Unit Testing Default Implementation.

Update: "dynamic"
In experimenting with default implementations, I found that "dynamic" does not find members that only have default implementations.

Article: C# 8 Interfaces: "dynamic" and Default Implementation.

Access Modifiers
Previously, interface members were automatically public. Now, members can have access modifiers including private, protected, internal, and public.

There are things that we will explore deeper in future articles.

Public Members
Public members really aren't a change since that's all we had before. But we need to take a look at how interface defaults differ from class defaults. For example, if we do not specify an access modifier on a class member, it defaults to private. But if we do not specify an access modifier on an interface member, it defaults to public. Not a huge deal, but we need to be aware of those differences.

Update - Article Now Available: C# 8 Interfaces: Public, Private, and Protected Members.

Private Members
Private members are new. These are not accessible outside of the interface itself. On the surface, this does not seem very useful for an interface since it is all about enforcing members on a class/struct. But private methods can be used by other members that have default implementation.

Private members *must* have a default implementation (because there is no way to add implementation outside of the interface itself).

Along with this, we need to take a look at what happens to our code once we start using private members. Will standard refactoring work? How does this affect testing? Can we treat this type of code (method extraction, small pieces, etc.) the same way we treat code in classes?

Update - Article Now Available: C# 8 Interfaces: Public, Private, and Protected Members.

Protected / Internal Members
Protected and internal members are also new, and we need to explore a bit further. What are the use cases for protected members? Are they useful only when deriving interfaces from other interfaces?

Also, how do these members impact the implementing classes? The short answer is that protected and internal members must be implemented explicitly in the class. The longer answer will depend on the use cases that we can come up with.

Update - Article Now Available: C# 8 Interfaces: Public, Private, and Protected Members.

Static Members
Another new feature is that we can have static members in interfaces. This includes static methods, static fields, and static constructors. These static members need to have implementation code in the interface.

Again, there is much to explore here, particularly around use cases and implementation.

Static Methods
What are the use cases for static methods in interfaces? I can imagine that we could have an interface that *only* has static methods. This could be a glob of functions that can be used independently of any class. How would this differ from a static class that only has static methods? There is a lot to explore here.

Update - Article Now Available: C# 8 Interfaces: Static Members.

Static Fields
This one is really new since interfaces could not contain fields before. But the real restriction is that interfaces cannot have instance data. And that is still true. Instance fields are not allowed, but we can have static data at the interface / abstraction level.

There is a tutorial on the Microsoft docs site (https://docs.microsoft.com/en-us/dotnet/csharp/tutorials/default-interface-members-versions) which shows how to use static fields as parameters for default implementation methods. This is an interesting use case. Are there other use cases for static fields?

Update - Article Now Available: C# 8 Interfaces: Static Members.

Static Constructors
Interfaces can now have static constructors. What are the use cases for this? Static constructors can only access static members of the interface, so they could be useful for "new"ing up a static field (for example, a static field that is a List<T>).

Are there other uses for static constructors?

Other Features
There are a few other features that go along with the main items above. These are also worth a closer look.

Abstract Members
I previously wondered about the "abstract" modifier that is now allowed in interfaces. I didn't understand since interface members are "abstract" by default. But in looking into it further, "abstract" can be useful in an interface inheritance scenario.

If a base interface has a default implementation for a member, it is possible for a derived interface to mark that member as "abstract". This would have the effect of hiding the default implementation.

This gets interesting in the class implementations because a class that implements the inherited interface also implements the base interface. The class would need to implement the abstract member to satisfy the contract, but this is definitely worth taking a closer look at.

And just because this is possible doesn't mean we should do it. Are there good use cases for this?

Partial Interfaces
Previously "partial" interfaces were not allowed. Partial classes allow us to spread a class across different files. I have not seen widespread usage of this feature, but there are a few scenarios where it is useful. Interfaces now support this same "partial" functionality. It's worth taking a closer look at this to see what types of scenarios would need this.

Static Main
Another thing that I found in the design proposal is that "static Main" is supported in interfaces. I have not yet looked at this, but it will be interesting to explore further.

Update - Article Now Available: C# 8 Interfaces: Static Main -- Why Not?
Update2 - Another article: Misusing C#: Multiple Main() Methods

Struct and Default Implementation
There is a "wart" [terminology from the proposal] when it comes to structs and default method implementation. The interface methods are not available in the struct the same way they are in a class. So to get to the default implementation, it requires boxing the struct. I have not seen a lot of structs that implement interfaces. And guessing from the decision to leave it like this, I suspect that the language designers have not seen much of it either. This is more a curiosity than something you're likely to need to deal with.

Lots to Explore
That's my list of things that need further exploration. I'll be diving into these as soon as I get the release bits of .NET Core 3.0 and the latest Visual Studio 2019 updates.

If you have any ideas for use cases mentioned above, or there are other areas that you'd like me to take a closer look at, be sure to leave a comment.

Be sure to check back because there's lots to explore.

Happy Coding!

Sunday, September 1, 2019

Interfaces in C# 8 are a Bit of a Mess

Interfaces are getting a significant overhaul in C# 8. I've been looking at some of the features, and I'm frankly stumped at some of the decisions that have been made. I'm also a bit disappointed at the messaging from Microsoft regarding these new features.

I'll start out by saying that I may be completely missing the point. So feel free to leave your comments. I'm looking for any help I can get at this point.

Code for this article (and further experimentation) is available on GitHub: jeremybytes/interfaces-in-csharp-8. Note: at the time of this writing, the code uses .NET Core 3.0 Preview 8.

Some of the new features include the following:
  • Default implementation for interface members
  • Access modifiers - public, private, protected, internal
  • abstract members
  • static members
Let's start by looking at default implementation.

Default Implementation of Interface Members
Default implementation has been the most widely-touted enhancement to interfaces in C# 8. Mads Torgersen wrote an article on the topic: https://devblogs.microsoft.com/dotnet/default-implementations-in-interfaces/. This article has the example that I've seen repeated when this topic is brought up.

The assumption is that we have an interface with a single member, and a class that implements that interface.

Then another member is added to the interface. To keep the existing implementations from breaking, we add default behavior to the new interface member.

Here is an ILogger interface that has 2 members. The second has a default implementation (this is in the ILogger.cs file in the GitHub project):


The original class only implements the first member (this is in the InitialLogger.cs file in the GitHub project):


Since the 2nd member (the Log method that takes an exception parameter) has a default implementation, this code builds just fine.

We can put together a little console application that shows that both methods work (this is in the Program.cs file in the GitHub project);


The output shows that calls to both of the Log methods work:


Of course, we are also free to provide an implementation of the 2nd member in the class. This would hide the default implementation.

My Thoughts
When I first heard of this feature, I thought it was a bad idea. This blurs the line between an abstract class (that contains implementation) and an interface (no implementation).

My recommendation would be to avoid default implementation for a few reasons.

First, I have only seen trivial examples where a good default exists. Most of our code is more complicated than that. If I want to add "Save" functionality to my API, there is probably no good default for that. If I end up throwing a NotImplementedException as a default, then that doesn't accomplish anything other than moving compile-time errors to run-time errors.

Second, we already have a way to extend functionality of an interface -- through interface inheritance. By creating a new "extended" interface that inherits from the original, the existing interface implementations continue to work. And if a client needs the extended functionality, then the client can use the new extended interface (this also helps us follow the interface segregation principle).

Third, interfaces are a difficult enough concept as it is. When I started programming professionally, it took me a good 2 years before I really understood interfaces and what they were good for. This was such a frustration to me that I've spent the last 7-1/2 years helping developers understand interfaces (this includes 33 live presentations, various blog articles, and a Pluralsight course that has over 100,000 unique viewers). If nothing else, this points out that the topic can be a challenge for developers to grasp.

Messaging from Microsoft
Most of the messaging from Microsoft has been around this -- adding functionality to an existing API. The idea that if you have an existing interface, you can add to it without breaking the initial implementations.

But it turns out that this is not the only reason this feature was added to the language.

For this, we can turn to C# 8 Language Design Proposals. Here is the article for default implementation: https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-8.0/default-interface-methods.

There are 3 reasons stated for this change: (1) extending APIs, (2) interoperability with Android (Java) and iOS (Swift), (3) supporting the "traits" language feature.

"Traits" are really a way of doing mix-ins with classes. The idea is that small groupings of code can be combined to form classes.

I think that traits can be a good idea; however, I think that using interfaces to implement that feature is a mistake. Another construct in C# would be less confusing to developers (even if it compiles down to the same IL).

To show the confusion that's on its way, let's take a look at some of the other changes to interfaces that facilitate these features.

Access Modifiers
Previously, access modifiers were not allowed on interface members. Here's an example from a .NET Framework 4.7.2 project:


Previously, all interface members were automatically visible. We weren't even allowed to mark something as "public". If we think of interfaces as a contract, then it makes sense that we are not allowed to use access modifiers. The terms of the contract need to be visible to everyone -- both the clients and the implementing classes.

But things are different with C# 8. We can have access modifiers. Here's an example of an interface that has a "protected" member (this is in the IReader.cs file in the GitHub project):


This causes a bit of confusion when implementing the interface. Mainly because the tooling isn't there yet. (I'm hoping it will be there soon; .NET Core 3.0 releases in 3 weeks.)

If we create a new class and mark it with the interface, we get the standard errors that there are members that are not implemented:


Note: since the Save method has a default implementation, it does not show up with the missing members.

I use the Ctrl+. shortcut to implement interfaces (or use the light bulb helper):


This, however, only implements the non-protected member. So if we use this "fix" and try to build, we still get errors:


The protected member is still not implemented.

To implement the protected member, we need to do an explicit implementation. This associates the method explicitly with the interface. This is another option on the Ctrl+. menu:


But if we do this, it implements *both* of the methods explicitly:


Note: Regardless of whether we use "Implement interface" or "Implement interface explicitly". The Save method (which has a default implementation) is not included. If we want to override that behavior, we need to type that in ourselves.

Now we have 2 implementations for "GetItem": one associated with the class, and one associated with the interface. This is probably not what we want.

You can take a look at the IntReader.cs file in the GitHub project to see the implementation that is probably more inline with what we want in this case:


This is a tooling problem. It can be fixed in Visual Studio, but it opens the door to some of the other things that come up when we have access modifiers on interface members.

Private Members
Since we can add access modifiers to interface members, we can have "private" members.


[Update Note: This example is quite embarrassing since I added a "Save" method to an "IReader" interface. You shouldn't do this. At the time, I was experimenting with syntax and wasn't thinking about the interface itself. Then this article got a bit more popular than I was expecting. More well thought out articles are available here: A Closer Look at C# 8 Interfaces.]

In this code, the "Save" method is marked as "private". The compiler will only let you mark a member as "private" if it has an implementation. So that's good.

But what would we do with a private interface member? The answer is not much. It is not accessible outside of the interface, so it is really only good if we want to create a method that will be used in other default implementations in the interface.

At this point, we're really creating a class, and an abstract class would be a much better solution.

Abstract Members
The thing that make me go  O_o  is the fact that we can have "abstract" interface members. The following code is valid and builds (this is the final IReader.cs file from GitHub):


In this code, the "GetItem" method is marked as "abstract".

What does this even mean? When we're dealing with abstract classes, abstract members have a declaration but not implementation. That describes *everything* in an interface (okay, it described everything in an interface until we had default implementation).

I'm a bit confused by this. The code behaves the same way whether the "abstract" is here or not.

I'll need to do a bit more research to find out why this is necessary.

Static Members
Interfaces can also have static members. This is something that is brand new. Statics were not allowed at all in interfaces previously.

If you're curious about using static members in interfaces, take a look at the tutorial: Update interfaces with default interface members in C# 8.0. This example shows how static members can be used to parameterize default implementations.

My Thoughts
Static members break the spirit of interfaces. Interfaces have to do with describing a contract -- something that a client can rely upon being there and an implementer has to include. The tutorial shows using static fields to hold data. Those are now implementation details.

My Thoughts
In my view, interfaces in C# 8 are a bit of a mess. We can no longer think of them as a contract. They are no longer the "shape" of a set of members in a class or struct. Instead, they can contain implementation. The members are no longer automatically visible, they can be private, protected, or internal.

I may be completely missing the point. But I can no longer answer the question: "What is an interface?"

An interface is no longer one thing. It has multiple aspects depending on how we want to use it. It will take a while to make sense of the new world. If you want to share your views, please leave a comment. I'm looking for clarification and to gain a better understanding of the changes.

Update: More thoughts here (a bit more organized, too) - A Closer Look at C# 8 Interfaces.

Stay tuned to the GitHub project (jeremybytes/interfaces-in-csharp-8). There will be more samples added and more articles. Together we can figure this out.

Happy Coding!

Saturday, August 24, 2019

Converting .NET Framework to .NET Core - UseShellExecute Has a Different Default Value

I came across a difference between .NET Framework and .NET Core that caused a bit of frustration when I was converting a project.
Process.StartInfo.UseShellExecute defaults to "true" in .NET Framework, but it defaults to "false" in .NET Core.
If you have code using Process, this may come up when converting your projects over to .NET Core.

Discovery and Pain
.NET Core is the path forward. And I have been slowly converting my code from .NET Framework to .NET Core. This is especially interesting because I can now move my WPF projects over to .NET Core 3 (which will be released in about a month).

Yesterday, I was converting my maze generation program (GitHub: jeremybytes/mazes-for-programmers) and ran into an issue. This program generates a maze using a selected algorithm and outputs it as a text maze (using ASCII art) as well as a graphical maze (using a bitmap). The bitmap gets saved to the file system as a .png file.

The application itself is a console application, and I want to show the graphical maze after it is saved to the file system. So, I do a Process.Start to have Windows open up the file using the default bitmap viewer. Here is the code for that (code can be found in Program.cs of the DrawMaze project):


This works fine with .NET Framework. But when I ran it in .NET Core, I got a runtime exception.


"System.ComponentModel.Win32Exception; 'The specified executable is not a valid application for this OS platform.'"

This left me scratching my head.

There was something wrong with the Process.Start. This is not something I do regularly, but I do know that "StartInfo" has a lot of properties. So I started fumbling around looking for answers.

Google & StackOverflow were not very helpful -- probably because I didn't know what to search for.

One thing I tried was changing the file name to ".\maze.png". You need to use a ".\" in PowerShell to execute something, so I thought maybe I needed it here. That didn't work.

Another thing I tried was changing the "FileName" property to "cmd.exe" and adding an "Argument" property that had "maze.png". That didn't work.

Then I started looking through the docs for Process and more specifically StartInfo.

UseShellExecute
Eventually, I ended up at the "UseShellExecute" property (docs) and found this little gem:


"The default is true on .NET Framework apps and false on .NET Core apps."

o_O

As soon as I saw this, I knew it was my problem. This property determines whether to use the operating system shell to start a process.

When it is "true", it's basically the same as typing "maze.png" from a command prompt. If you do this from a Windows command prompt, it will will try to open the file using the default image viewer.

But if it is "false", then we're saying "execute this file", and a bitmap is not an executable.

Fixing the Code
The code fix was easy after that. I just had to set the UseShellExecute property to "true":


Then the program worked. On my machine it opens the "Photos" app, which is my default viewer.


(And in case you're curious, here's the full image of the maze that was generated -- be sure to zoom in to see all the interesting detail)


Cross-Platform Solution?
I find the cross-platform features of .NET Core to be particularly interesting. So I've been trying a bunch of my .NET Core projects on MacOS and on Linux.

I have not figured out how to do something like this in a cross-platform-friendly way. The text maze generation in a console/terminal window works just fine. The bitmap is created and saved to the file system just fine. But I'm not sure how to display the bitmap file automatically. I'm really relying on the default Windows behavior in the current application.

One potential solution is to put in some OS-specific code. If it is Windows, do a shell execute. If it is MacOS, open up the "Preview" application with the bitmap file. But there's really no equivalent in the Linux world. What I'd like to do is "open this bitmap with the default bitmap viewer". That doesn't exist on Linux.

Another idea is to open the file in a browser. But there's no guarantee that a particular browser is available on a particular platform.

If you have any ideas, be sure to leave a comment on this article.

Wrap Up
I really like .NET Core, and I'm excited for the Core 3 release so I can start using it with my WPF application on Windows.

.NET Core is the path forward. So far, moving code over to new projects has been fairly painless. But I have run into a few issues like this one that are a bit frustrating. This is a breaking change between platforms.

I did not run this application through the .NET Portability Analyzer. This application is small and straight forward -- a console application and a couple of libraries that aren't doing anything exciting; they don't even use any external NuGet packages. I should probably run it through the analyzer to see if it finds this change between the platforms.

I'll be sure to post any other strangeness I find when doing my conversions. And I'm hoping to do a walkthrough of an entire application conversion sometime soon.

Happy Coding!