Why I don’t like extension methods (the way it is)
Back in the day and since then, C# 3.0 introduced a new syntactic sugar feature called extension methods. The idea is to be able to call a static method which defines as its first parameter an object of a certain type as though this static method were actually an instance method of that object.
So, instead of having to write
Foo(obj, arg1);
you’d write
obj.Foo(arg1);
the method’s signature being, say
public static string Foo(this MyClass obj, string arg1);
This is really a big deal for generic fluent APIs like LINQ. And since both features came with the same major version of C#, extensions methods were most probably introduced as a means of making LINQ (more specifically: LINQ extension methods) feasible and enjoyable in C#.
At first, this seems harmless and even a great idea, if it weren’t for a small detail. And I could only notice it after I learned about a specific feature in F#.
So what my issue with extension methods is
The intention of improving the syntax of calling static methods is something I actually appreciate. What I don’t like about extension methods is how this intention was implemented.
Not being able to tell a legit instance method from a foreign static method can be at times (or even often) annoying and time-consuming. It also decreases the expressiveness of the language since whenever you’re reading a method call you have to ask yourself: “ok, but what am I really looking at there: is this an instance method or an extension method?”
The remedy to this disadvantage is really simple and kind of obvious, to be honest: the syntax for calling extension methods should be slightly different than the syntax for calling a normal instance method!
For comparison, in many functional programming languages, like in F#, there’s a syntax feature called “pipe” which basically accomplishes the goal of extension methods.
So, in F# a code analogous to the above C# example would be:
obj |> foo arg1
the function’s signature being, say
foo: string -> MyClass -> string
which reads: “foo is a function that takes a string and then takes a MyClass in order to yield a string”
It means you could write the following F# snippet to the same effect of using the pipe as in the above example
foo arg1 obj
The pipe operator does a very simple job: it makes the function on its right (foo) use the value on its left (obj) as the function’s next argument. So, you just rearrange the argument in the call.
The pipe operator is therefore a syntactic sugar, just like extension methods in C#, but it doesn’t try to mislead you into thinking it’s an instance method of that object.
By the way, in F# you can also call an object’s instance method and when you do that, you use the dot, just like you would in C#. This is F# syntax for calling an instance method of an object:
obj.MyLegitMethod(arg2)
Alternative and wrapping it up
An alternative to the current extension methods syntax doesn’t have to be pipes, especially because people with some experience in functional programming would then also expect C# to provide built-in currying (a.k.a higher order functions, a.k.a partial functions), it just takes an alternative to the standard “dot” syntax. I’d be fine with, say:
obj..Foo(arg1)
Or even:
obj->Foo(arg1)
most important: it just has to be different from obj.Foo(arg1).
This late change probably will never come, given that extension methods have been around for a long while, are already an established syntax and most people don’t even realize it’s not an optimal solution, but I hope this post makes you curious about learning more about functional programming and its clever features.