Extension Methods are the Devil

There are a few instances where I see extension methods being valuable and saving you from excess typing.  The biggest one would be a set of extensions that bring all of the lovely members of List to their respective IEnumerable/ICollection/IList brethren.  Along the lines of:

public static void AddRange<T>(this ICollection<T> col, IEnumerable<T> collection)

public static ReadOnlyCollection<T> AsReadOnly<T>(this ICollection<T> col)

public static ICollection<T> ConvertAll<T, TOutput>(this IEnumerable<T> col, Converter<T, TOutput> converter) etc...

Any other use of extension methods will force me to stab you in the eye and cut off your right pinky finger, making it impossible for you to type the semi-colon (;) character and relegating you to the ranks of VB.Net programmers the resulting humiliation of which should cause you to finish the job yourself.

Let me summarize the short comings of extension methods and pick on the MvcToolkit as an abusing offender.  Read more bloggers (Derik, John, and Karl)  who agree with me in spirit if not in eye-stabbing, pinky severing practice.

Extension Methods...

  • Should be used sparingly. (Wear goggles and a gauntlet while you make your case to me, just to be safe)
  • Are nothing more than a compiler trick.
  • Are achievable through more discoverable means.
  • Are NOT mixins.
  • Are not overrideable.
  • Are not discoverable at run-time.
  • Will cause you pain.
  • Should absolutely NOT be used to add methods to classes for which you own the source code.

Consider the following code which compiles:

namespace Pain
{
  using ExtensionMethods.AreThe;

  public enum Eye { Left, Right }

  public class ExtensionMethodUserPunisher
  {
    public void StabEye()
    {
      this.StabEye(Eye.Left);
    }

    public void SeverPinky()
    {
    }
  }
}

namespace ExtensionMethods.AreThe
{
  using Pain;

  public static class Extensions
  {
    public static void StabEye(this ExtensionMethodUserPunisher subject, Eye eye)
    {
    }
  }
}

Now consider this almost identical code, which does not compile:

namespace Pain
{
  using ExtensionMethods.AreThe;

  public enum Eye { Left, Right }

  public class ExtensionMethodUserPunisher
  {
    public void StabEye()
    {
      StabEye(Eye.Left);
    }

    public void SeverPinky()
    {
    }
  }
}

namespace ExtensionMethods.AreThe
{
  using Pain;

  public static class Extensions
  {
    public static void StabEye(this ExtensionMethodUserPunisher subject, Eye eye)
    {
    }
  }
}

Now consider what happens if you modify your using statement:

namespace Pain
{
  using ExtensionMethods.AreThe.Devil;

  public enum Eye { Left, Right }

  public class ExtensionMethodUserPunisher
  {
    public void StabEye()
    {
      this.StabEye(Eye.Left);
    }

    public void SeverPinky()
    {
    }
  }
}

namespace ExtensionMethods.AreThe
{
  using Pain;

  public static class Extensions
  {
    public static void StabEye(this ExtensionMethodUserPunisher subject, Eye eye)
    {
    }
  }
}

namespace ExtensionMethods.AreThe.Devil
{
  using Pain;

  public static class Extensions
  {
    public static void StabEye(this ExtensionMethodUserPunisher subject, Eye eye)
    {
      subject.SeverPinky();
    }
  }
}

You code still compiles just fine, but you will get different behavior and it should be fun tracking down why.

Oh but you can abuse any language feature, and you would never do something like this, and this is never going to happen to you, and you are going to extend the crap out of System.Object because you can.  Fine, but when the time comes I'm not even going sully my pen with your ocular juices.

Back to the MvcToolkit.  Rob's eye get a grace period, because this is only a CTP.  I'm not privy to the internal workings of the MVC team so I'm not sure why this was initially developed as a separate assembly.  I know that the plan is to move it into System.Web.Extensions.  I hope that when it is moved that all of the 75+ HtmlHelper extension methods become first class members.  Here's why:  Not all consumers of HtmlHelper are compiled, making extension methods pretty useless.  And maybe I want to override the output of TextBox without re-writing the whole method and without resorting to the mess demonstrated above.

Please feel free to flame me with your comments exhorting the virtues of extension methods.

posted @ Friday, January 04, 2008 12:41 PM


Print

Comments on this entry:

# Extension Methods are the Devil

Left by DotNetKicks.com at 1/4/2008 2:41 PM

You've been kicked (a good thing) - Trackback from DotNetKicks.com

# re: Extension Methods are the Devil

Left by Rob Conery at 1/4/2008 6:16 PM
Gravatar

>>>Oh but you can abuse any language feature, and you would never do something like this, and this is never going to happen to you, and you are going to extend the crap out of System.Object because you can. Fine, but when the time comes I'm not even going sully my pen with your ocular juices.<<<

The MS crowd, I find, is a very thoughtful one - each time a new feature is introduced, people worry themselves into a sweat over how "the other guy" will abuse it :):). And at the same time threaten my eyes... :):)

We had a big long discussion about putting UpdateFrom() on Object (which, I think, is the guilty party based on your post). I changed it before publishing to "hang off" of INotify (used for LinqToSql objects) but it was mentioned, quite rightly, that it should be usable by all objects.

We then decided to move the namespace (actually ScottGu did that) to "System.Web.Mvc.BindingHelpers" so that you'd need to explicitly "declare" the namespace in order to access the method. I think that's pretty clean - mixin or not.

>>Are nothing more than a compiler trick<<
I think you can put Anonymous Types, LINQ, and most of C# 3.5 into the "Compiler Trickery" camp - for better or worse. Keep in mind that all dynamic languages are essentially "compiler tricks" that abstract away what a compiler does (in essence). I find it fascinating that the C# team has built this in.

All that aside- your feedback is really appreciated but I'll be honest, I didn't really "get" your title and I'm not sure why it's evil, aside from not managing your namespacing well - which is always a concern isn't it?

I see it in the reverse - the amount of code I can reduce by using these things is enormous, as long as I allow people to "opt in" by using "SubSonic.XXX.Extensions" (I'm still working on the naming).

Anyway - curious to know more here - if you can add some detail to what you see as a problem with the Toolkit (other than UpdateFrom) I'd appreciate it.

# Link Listing - January 4, 2008

Left by Christopher Steen at 1/4/2008 10:57 PM

ASP.NET Scaffolding in ASP.NET: Dynamic Data Support [Via: infoq.com ] Unit Testing ASP.NET Pages Using...

# Link Listing - January 4, 2008

Left by Christopher Steen at 1/4/2008 10:58 PM

Link Listing - January 4, 2008

# re: Extension Methods are the Devil

Left by Hernan Garcia at 1/4/2008 11:08 PM

Having using some very powerful dynamic languages and having doing tons of Ajax with Javascript I have come to love the posibility of "extend" the given language I'm working on.

I think that the key is what Rob is saying, being able to know exactly where your extension methods are so they don't appear just like magic.

I undestand your concerns but the same maybe said about most of the new features. My main concern maybe that two libraries declare the same extension name for the same object but do two different things.

I did a quick test and the compiler seems to decide for you witch one to use if one extension is in your project and the other come from an external library, given priority to the one in the namespace of your app.
Now if the extensions are in two external libraries, the app won't compile (what is good and prevent you to shoot in your foot).

Nice post, it's good to see this post now, so we think carefully before using any of the new features and we don't get caught in the hype.

# re: Extension Methods are the Devil

Left by David Fauber at 1/16/2008 12:02 PM
Gravatar

I've made extensive use of them on one home project (the one I used to pull scores off the web and generate the html pages in my rankings link above), but not at work yet.

When we adapt 3.5 at work, I'm unsure how much I'll use them. They make me feel dirty but not filthy. When I realized they were just "syntactic sugar" and not anything magical, it actually made me feel better about using them.

I do strongly agree with your statement about not using them for classes where you own the source.

Your comment:



 (will not be displayed)


 
 
 
Please add 6 and 3 and type the answer here:
 

Live Comment Preview:

 
«July»
SunMonTueWedThuFriSat
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789