Prefer extension methods for encapsulation and reusability?
Posted
by tzaman
on Stack Overflow
See other posts from Stack Overflow
or by tzaman
Published on 2010-06-14T12:41:09Z
Indexed on
2010/06/17
8:33 UTC
Read the original article
Hit count: 452
edit4: wikified, since this seems to have morphed more into a discussion than a specific question.
In C++ programming, it's generally considered good practice to "prefer non-member non-friend functions" instead of instance methods. This has been recommended by Scott Meyers in this classic Dr. Dobbs article, and repeated by Herb Sutter and Andrei Alexandrescu in C++ Coding Standards (item 44); the general argument being that if a function can do its job solely by relying on the public interface exposed by the class, it actually increases encapsulation to have it be external. While this confuses the "packaging" of the class to some extent, the benefits are generally considered worth it.
Now, ever since I've started programming in C#, I've had a feeling that here is the ultimate expression of the concept that they're trying to achieve with "non-member, non-friend functions that are part of a class interface". C# adds two crucial components to the mix - the first being interfaces, and the second extension methods:
- Interfaces allow a class to formally specify their public contract, the methods and properties that they're exposing to the world.
- Any other class can choose to implement the same interface and fulfill that same contract.
- Extension methods can be defined on an interface, providing any functionality that can be implemented via the interface to all implementers automatically.
- And best of all, because of the "instance syntax" sugar and IDE support, they can be called the same way as any other instance method, eliminating the cognitive overhead!
So you get the encapsulation benefits of "non-member, non-friend" functions with the convenience of members. Seems like the best of both worlds to me; the .NET library itself providing a shining example in LINQ. However, everywhere I look I see people warning against extension method overuse; even the MSDN page itself states:
In general, we recommend that you implement extension methods sparingly and only when you have to.
(edit: Even in the current .NET library, I can see places where it would've been useful to have extensions instead of instance methods - for example, all of the utility functions of List<T>
(Sort
, BinarySearch
, FindIndex
, etc.) would be incredibly useful if they were lifted up to IList<T>
- getting free bonus functionality like that adds a lot more benefit to implementing the interface.)
So what's the verdict? Are extension methods the acme of encapsulation and code reuse, or am I just deluding myself?
(edit2: In response to Tomas - while C# did start out with Java's (overly, imo) OO mentality, it seems to be embracing more multi-paradigm programming with every new release; the main thrust of this question is whether using extension methods to drive a style change (towards more generic / functional C#) is useful or worthwhile..)
edit3: overridable extension methods
The only real problem identified so far with this approach, is that you can't specialize extension methods if you need to. I've been thinking about the issue, and I think I've come up with a solution.
Suppose I have an interface MyInterface
, which I want to extend -
I define my extension methods in a MyExtension
static class, and pair it with another interface, call it MyExtensionOverrider
. MyExtension
methods are defined according to this pattern:
public static int MyMethod(this MyInterface obj, int arg, bool attemptCast=true)
{
if (attemptCast && obj is MyExtensionOverrider)
{
return ((MyExtensionOverrider)obj).MyMethod(arg);
}
// regular implementation here
}
The override interface mirrors all of the methods defined in MyExtension
, except without the this
or attemptCast
parameters:
public interface MyExtensionOverrider
{
int MyMethod(int arg);
string MyOtherMethod();
}
Now, any class can implement the interface and get the default extension functionality:
public class MyClass : MyInterface { ... }
Anyone that wants to override it with specific implementations can additionally implement the override interface:
public class MySpecializedClass : MyInterface, MyExtensionOverrider
{
public int MyMethod(int arg)
{
//specialized implementation for one method
}
public string MyOtherMethod()
{ // fallback to default for others
MyExtension.MyOtherMethod(this, attemptCast: false);
}
}
And there we go: extension methods provided on an interface, with the option of complete extensibility if needed. Fully general too, the interface itself doesn't need to know about the extension / override, and multiple extension / override pairs can be implemented without interfering with each other.
I can see three problems with this approach -
- It's a little bit fragile - the extension methods and override interface have to be kept synchronized manually.
- It's a little bit ugly - implementing the override interface involves boilerplate for every function you don't want to specialize.
- It's a little bit slow - there's an extra
bool
comparison and cast attempt added to the mainline of every method.
Still, all those notwithstanding, I think this is the best we can get until there's language support for interface functions. Thoughts?
© Stack Overflow or respective owner