C# prefers composition to inheritance yet lacks any concise composition syntax. This is unfortunate. While I have nothing against composition, I really don’t like the redundancy of manually forwarding methods. Here I propose a simple syntax that would make composition simple and painless.
The example
Composition in C# currently looks like the below code. If you do a lot of Java you’ll also be familiar with this.
1 2 3 4 5 6 7 8 9 10 11 12 |
public class Composed : ISomething { SomethingImpl impl; //manual kludge public void FirstMethod( int a, int b ) { impl.FirstMethod( a, b ); } public string SecondMethod( float c, Type[] d ) { return impl.SecondMethod( c, d ); } } |
It’s a bit weird that neither C# nor Java have a succinct way to compose classes. Most other common languages do. In C++ this can be handled with multiple inheritance, though the syntax is kind of odd. Python also has multiple inheritance. Ruby is known for its mixins, which also appear in PHP now. Several languages have explicit traits system. Perl seems to have traits, mixins, and multiple inheritance.
I propose the below syntax to make this much nicer.
1 2 3 4 5 |
public class Composed : ISomething { SomethingImpl impl; proxy impl as ISomething; } |
In contrast to the murky manual proxying this explicit proxy
code expresses clearly what I intend. I want the entire ISomething
interface from SomethingImpl
to be exposed in my Composed
class. This is equivalent to manually forwarding all of the individual interface methods with the exact same name and parameters.
This avoids potential defects with mistyping the names, types or parameters. Should the interface change I can also leave my code exactly as is. It automatically changes along with the interface. These are both great points for code maintenance.
Selection of proxy
The as ISomething
is an important part of the syntax. Typically our implementations need to have far more public methods than what the interface provides. Otherwise it may not be very usable form the Composition
class itself. A syntax without the as
part would thus expose too many details.
1 2 3 4 5 6 |
public class PoorlyComposed : ISomething { SomethingImpl impl; //would include all public methods in SomethingImpl proxy impl; } |
I can nonetheless see value in proxying all public methods, so perhaps this syntax should also be allowed. But for the most part you’d likely only want to expose a limited subset. In this case you want something to implement the ISomething
interface and nothing more.
We might want even more fine-grained control over what happens. Let’s also allow for proxying individual functions.
1 2 3 4 5 6 7 |
public class PiecewiseComposed : ISomething { SomethingImpl impl; proxy impl.FirstMethod; public string SecondMethod( float c, Type[] d ) { ... } } |
Here we proxy the FirstMethod
and manually implement SecondMethod
.
We might want one additional feature dealing with larger interfaces. Suppose you wish to proxy almost all of the interface, but override just one or two methods. This could be allowed using the current override
syntax.
1 2 3 4 5 6 7 |
public class MinimallyComposed : IComplex { ComplexImpl impl; proxy impl as IComplex; public override int ComplexMethod( int a ) { ... } } |
Implementation
This feature should be relatively easy to implement as it requires no additional runtime support. The compiler can quite simply translate these proxy statements into the normal proxying code. The definition of the interface and the implementation are already required, so it doesn’t introduce any new dependencies. Nor does it introduce any kind of new typing rules or semantics.
I would love to see this added to the language. It significantly reduces redundancy in composing classes, improves code clarity, and makes maintenance easier.
If like to explore languages and compilers then follow me on Twitter. I always have more ideas and things to uncover. If there’s something special you’d like to hear about, or want to arrange a presentation feel free to contact me.