views:

849

answers:

7

Rails introduced some core extensions to Ruby like 3.days.from_now which returns, as you'd expect a date three days in the future. With extension methods in C# we can now do something similar:

static class Extensions
{
    public static TimeSpan Days(this int i)
    {
        return new TimeSpan(i, 0, 0, 0, 0);
    }

    public static DateTime FromNow(this TimeSpan ts)
    {
        return DateTime.Now.Add(ts);
    }
}

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine(
            3.Days().FromNow()
        );
    }
}

Or how about:

static class Extensions
{
    public static IEnumerable<int> To(this int from, int to)
    {
        return Enumerable.Range(from, to - from + 1);
    }
}

class Program
{
    static void Main(string[] args)
    {
        foreach (var i in 10.To(20))
        {
            Console.WriteLine(i);
        }
    }
}

Is this fundamentally wrong, or are there times when it is a good idea, like in a framework like Rails?

+5  A: 

Personally I like int.To, I am ambivalent about int.Days, and I dislike TimeSpan.FromNow.

I dislike what I see as a bit of a fad for 'fluent' interfaces that let you write pseudo English code but do it by implementing methods with names that can be baffling in isolation.

For example, this doesnt read well to me:

TimeSpan.FromSeconds(4).FromNow()

Clearly, it's a subjective thing.

mackenir
Thatismatt didn't specify int.Days, rather the example he cited was TimeSpan.Days. Could you correct, please?
Neil Barnwell
@Neil - the Days extension method extends int to return a TimeSpan.
mackenir
+6  A: 

I like extension methods a lot but I do feel that when they are used outside of LINQ that they improve readability at the expense of maintainability.

Take 3.Days().FromNow() as an example. This is wonderfully expressive and anyone could read this code and tell you exactly what it does. That is a truly beautiful thing. As coders it is our joy to write code that is self-describing and expressive so that it requires almost no comments and is a pleasure to read. This code is paramount in that respect.

However, as coders we are also responsible to posterity, and those who come after us will spend most of their time trying to comprehend how this code works. We must be careful not to be so expressive that debugging our code requires leaping around amongst a myriad of extension methods.

Extension methods veil the "how" to better express the "what". I guess that makes them a double edged sword that is best used (like all things) in moderation.

Andrew Hare
I suppose the same logic would take us all the way back to assembly, but you're right: encapsulation, especially when done poorly, is does come with a cost.
Robert Gowland
@slowplay - The point about extension methods is that they break encapsulation
Sam Meldrum
A: 

I'm on the conservative side of the spectrum, at least for the time being, and am against extension methods. It is just syntactic sugar that, to me, is not that important. I think it can also be a nightmare for junior developers if they are new to C#. I'd rather encapsulate the extensions in my own objects or static methods.

If you are going to use them, just please don't overuse them to a point that you are making it convenient for yourself but messing with anyone else who touches your code. :-)

siz
A: 

Each language has its own perspective on what a language should be. Rails and Ruby are designed with their own, very distinct opinions. PHP has clearly different opinions, as does C(++/#)...as does Visual Basic (though apparently we don't like their style).

The balance is having many, easily-read, built-in functions vs. the nitty-gritty control over everything. I wouldn't want SO many functions that you have to go to a lookup every time you want to do anything (and there's got to be a performance overhead to a bloated framework), but I personally love Rails, because what it has saves me a lot of time developing.

I guess what I'm saying here is that if you were designing a language, take a stance, go from there, and build in the functions you (or your target developer would) use most often.

Jon Smock
+3  A: 

First, my gut feeling: 3.Minutes.from_now looks totally cool, but does not demonstrate why extension methods are good. This also reflects my general view: cool, but I've never really missed them.


Question: Is 3.Minutes a timespan, or an angle?

Namespaces referenced through a using statement "normally" only affect types, now they suddenly decide what 3.Minutes means.

So the best is to "not let them escape".
All public extension methods in a likely-to-be-referenced namespace end up being "kind of global" - with all the potential problems associated with that. Keep them internal to your assembly, or put them into a separate namespace that is added to each file separately.

peterchen
+1  A: 

I agree with siz and lean conservative on this issue. Rails has that sort of stuff baked in, so it's not really that confusing ever. When you write your "days" and "fromnow" methods, there is no guarantee that your code is bug free. Also, you are adding a dependency to your code. If you put your extension methods in their own file, you need that file in every project. In a project, you need to include that project whenever you need it.

All that said, for really simple extension methods (like Jeff's usage of "left" or thatismatt's usage of days.fromnow above) that exist in other frameworks/worlds, I think it's ok. Anyone who is familiar with dates should understand what "3.Days().FromNow()" means.

Ed Schwehm
A: 

My personal preference would be to use them sparingly for now and to wait to see how Microsoft and other big organizations use them. If we start seeing a lot of code, tutorials, and books use code like 3.Days().FromNow() it makes use it a lot. If only a small number of people use it, then you run the risk of having your code be overly difficult to maintain because not enough people are familiar with how extensions work.

On a related note, I wonder how the performance compares between a normal for loop and the foreach one? It would seem like the second method would involve a lot of extra work for the computer, but I'm not familiar enough with the concept to know for sure.

Mitchell Gilman