There used to have a wonderful series of “What If?” comics that pondered a few of the important hypothetical questions in the Marvel universe.
We talked about a few of the limitations of interfaces in C# on episode 1, and I wanted to provide a few examples of what we were on about with this fun little twist.
Let’s see what it could look if interfaces, static classes, and anonymous classes supported constructors and some theoretical workarounds for these limitations.
Among other things, We discussed the notion of “baking it in”: enforcing the rules of your application through grammar. The idea being that the next person to come along is steered towards the “pit of success” and don’t waste any time struggling with properties and methods that aren’t relevant or could be dangerously misused.
As mentioned on the podcast, one example of this could be using public interfaces as guardrails. These interfaces steer the callers of your library towards your intent instead of the nuts and bolts.
Another example of “baking it in” could involve creating explicit constructors for your classes that require, and therefore enforce, a valid state.
When it comes to software development, there are no right answers. However, there are lots of wrong ones.
We’re able to share constructors in C# via inheritance, but although interfaces are a contract, you cannot use them require any particular type of constructor.
So what?
Generic support in C# is fantastic and constraints are a very powerful aspect.
Despite the name, constraints actually enable behaviors by restricting the universe of objects to particular set of objects with shared behaviors. This enables the compiler and runtime to treat these objects in the same way. Nifty, eh?
C# even supports the “new()” constraint which requires the generic object to have a parameterless constructor. This makes it dead simple to create factory methods and other useful things…but other constructor signatures are not supported.
But, what if they did?
Let’s take a peek at the hypothetical syntax.
What if interfaces supported constructors?
In IL constructors are referenced as “ctor”, so we’ll use that as a generic way of requiring a constructor with a particular signature.
Sticking with the “What if?” theme, let’s assume an interface for a hero.
The interface requires a constructor taking two strings, and we’ve got two implementing classes. Mutants and Aliens. (I prefer aliens)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
interface IHero { ctor(string name, string power); } internal class Mutant : IHero { public Mutant(string name, string power) { ... } } internal class Alien : IHero { public Alien(string name, string power) { ... } } |
If interfaces supported constructors, then we could do something like this:
1 2 3 4 5 6 7 8 9 |
class MovieStudio { public IHero Reboot(T originalHero) where T:IHero { var rebootedHero = new T(originalHero.name, originalHero.power); MakeSillyAndUnnecessaryChanges(rebootedHero); return rebootedHero; } } |
“Reboot” acts as a factory method for creating new heroes. It doesn’t even need to know about what the underlying type is as our “what if” interface supports the constructor signature.
Also, remember that our mutant and alien classes were internal but the movie studio was able to create an instance, regardless of assembly, because the public interface supported the constructor. Our consumers don’t need to know how our sausage is made!
See, doesn’t that just feel right?
Workarounds
Parent classes can provide provide the constructor and the children can override as needed, however the generic support still falls short so forget about the generic factories.
Another solution could be to have the name and power be public properties, but assuming those fields are required we’re allowing classes to be created in an invalid state. At that point we’re no longer “baking it in!”
The *right answer here is probably to use a Dependency Injection framework. This allows you to enforce the rules of your application and insure the state of your objects through generics, anyone but the DI framework needing to know how to create objects.
*When it comes to software development, there are no right answers. However, there are lots of wrong ones.
What if interfaces supported static classes?
On the podcast I gave the example of pizza factories, which I lovingly borrowed from the Head First Design Patterns book. They both do the same thing, create pizzas, but they each have their own proprietary style.
Now, let’s assume that these factories are stateless, they have no member variables to keep track of anything. They simply take a string called “type” and return a new pizza.
This means that we’ll be able to call our MakePizza method without creating a new instance of our factory. This is an efficient implementation if we’re making a lot of pizza, and it lets the compiler enforce our singleton pattern rather than trying to do it ourselves (which is surprisingly complicated)
However, in C# there’s no way to assign an interface to a static class.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
interface IPizzaFactory { IPizza CreatePizza(IIngredients ingredients); } static class ChicagoPizzaFactory : IPizzaFactory // Can't do it! { public IPizza CreatePizza(String type) { ... } } static class NewYorkPizzaFactory : IPizzaFactory // Can't do it! { public IPizza CreatePizza(String type) { ... } } |
It’s easy to come up with a contrived use case, like a pizza contest that requests a pizza from each of the pizza factories. Wouldn’t it be nice if we could take a collection of these static classes and loop through them to request the pizzas?
Dream on.
1 2 3 4 |
IEnumerable GetThePizza(IEnumerable factories) { return factories.Select(x => x.CreatePizza()); } |
Why can’t interfaces support static classes?
Simply put, interfaces in C# don’t support static methods. At the time C# was written, java didn’t either but it looks like it will soon.
There’s a good discussion of this on StackOverflow here and here, but overall I feel like there’s a disconnect between the reasons why it doesn’t work and the interface-as-a-contract metaphor.
I would love to see this kink worked out in a future version of the CLR.
Workarounds
Singletons are often considered an anti-pattern, but you can easily save a lot of memory by only having one copy of your object. But there are other ways to do that.
And there’s always reflection, but it’s notoriously slow.
The simplest solution for this “problem” is to just cache one copy of your non-static factory, or you can be lazy and create it every time you need it.
Want to read more about factories and factory methods?
What if interfaces supported anonymous classes
Finally, my last and least nit.
You cannot assign an interface to an anonymous type. I assume there’s a good technical reason for this but the feature feels like it should be there. It feels missing to me.
I keep running into this one when I’m performing some linq magic and want to adapt one collection of items into another via the “Select” method.
This one doesn’t require a lot of imagination, but here’s an example of what it could look like.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
interface IHero { string Name { get; } string Power { get; } } IStudent { string Power { get; } } IEnumerable GiftedYoungsters { get; set; } IEnumerable CreateTeam(Name) { // return random team of 4 return GiftedYoungsters .OrderBy({} => Guid.NewGuid()) .Take(4) .Select(student => new { Name = RandomHeroName(), Power = student.Power } as IHero); } |
You can see the trick above on line 24. We create an anonymous class via the select and we “as” it to an IHero. Unfortunately the “as” always returns null because even though the interface would be fulfilled, it’s not officially assigned.
See, doesn’t that just feel right?
Workarounds
The only solution I can think of here is for the Select clause to return a new instance of a concrete class. For example, you could create a private nested class that implements IHero and return that instead of the anonymous object.
1 2 3 4 5 |
private class WishThisDidntExistHero : IHero { string Name { get; } string Power { get; } } |
It’s some extra typing, and we know that more lines = more bugs, but our hands are tied.
Conclusion
Interfaces are a very powerful and important feature of modern static object-oriented languages, but they do have their limitations.
You can read more about interfaces and how they work under the cover in CLR via C#.
We hope you enjoyed reading this, we’d love to hear your feedback so drop us a comment or email us at comments@codingblocks.net.