views:

515

answers:

11

One interesting aspect of extension methods in .NET is the fact that you can apply them to interfaces. For me, it seems nice that I can define functionality near the interface without defining an abstract class that clutters the assembly.

I know that abstract classes are not obsolete or anything, but how do you feel about utilizing this side effect in your code?

Example:

public static class IUserExtensions
{
    public static bool IsCurrentUser(this IUser user)
    {
        return (HttpContext.Current.User != null &&
                HttpContext.Current.User.Identity.Name == user.ID.ToString());
    }
}

public interface IUser {
    int ID { get; set; }
}
A: 

I have not used anything past .NET 2.0, so I had no idea you could do that. Seems weird to me; interfaces are not for implementations. I would find that confusing. Also, the example that you show is a class, not an interface.

Ed Swangren
That's just the extension wrapper. IUser is an actual interface.
BC
Still seems odd to me, but I haven't worked with anything above .NET 2.0, so I have things to learn once we switch over.
Ed Swangren
+1  A: 

No, abstract classes are not less attractive. Abstract classes provide the proper paradigm for object hierarchies.

Extension methods are only really useful if you need to add instance methods to an already existing class but can't modify the code directly.

Ben S
The performance characteristics should be the same because extension methods are linked in at compile time. Can you cite something that shows this is true?
BC
Do you have proof Abstract classes are faster? Please provide. If you look IL all an extension method is a static method call...I would be shocked if that is slower then calling a method on an abstract particularly a virtual method.
JoshBerke
Not to mention performance is one of the last things I tend to look at when deciding whether to use an ABC or an extension method... Architectural concerns come first; performance after profiling.
Erik Forbes
Hrm... I've been mislead, removed my comment about performance.
Ben S
You've also been mislead regarding the purpose of extension methods - they do not add instance methods; they are only syntactic sugar on top of static methods. Extensions do not violate encapsulation - that is, they cannot access private state.
Erik Forbes
@Erik to that point, they shouldn't modify state at all, because it makes it difficult to maintain where state is changed if you start to modify state outside of the object in question.
Michael Meadows
I agree completely, and was going to comment to the same effect on another answer - but forgot to as work intervened. =P
Erik Forbes
Sometimes the syntactic sugar is too sweet. I find it too easy to get carried away with extension methods. They should only be used as a last resort IMO.
Ben S
@Ben I agreee (mostly). As with all features that provide functionality outside of plain old OOP, extension methods should be used only when it does not add to complexity. One should always ask "how can I do this the old fashioned OOP way" first, and think carefully deciding.
Michael Meadows
+2  A: 

I do like extension methods because it has given me the ability to define Find(Predicate), Remove(Predicate) etc on IList<T> which I have been missing. I do not think you can say they are a replacement for abstract classes.

I have also defined extension methods to add generic behavior. I love my ToJson extension method on object or ToXml quite handy.

The only problem I have with your example is I always look IsCurrentUser as a property not a method and alas we have no extension properties. But I'm nitpicking

They are completly unrelated. I use an abstract class when I want to model a behavior, that others will implement or inherit.

JoshBerke
Don't forget IEnumerable<T>.ForEach(...);
Erik Forbes
Ohhh I have that one plus I have ReadOnlyCollection...I've not written them all yet but I keep adding to my little collection
JoshBerke
I think everyone's got a little collection - I have readability extension methods on IComparable<T> (IsGreaterThan, IsLessThan, etc), IEquatable<T> (IsEqualTo, IsNotEqualTo), etc.
Erik Forbes
I even toyed around with extensions on Int32 - consider: 5.Times(i => Console.WriteLine(i));
Erik Forbes
But that's just silly. =P
Erik Forbes
Well I wrote string.IsNull when I only cared if it was null...talk about useless
JoshBerke
+4  A: 

I have used this functionality several times - and in fact, this functionality was created specifically for the purpose of decorating interfaces without modifying them, hence LINQ. All the goodness that is LINQ (to Objects at least) is based on extension methods to IEnumerable<T>.

However, I don't feel that extension methods in any way replace abstract base classes for when you need them. Extension methods cannot access the extended class's private state - extension methods look like instances, but are still static.

Extension methods and abstract base classes solve two different types of problems, and the choice to use either of these paradigms should not depend on each other.

My answer to your title question is thus: No, the existence of Extension Methods do not make Abstract Base Classes less attractive. If one believes that the existence of Extension Methods makes Abstract Base Classes less attractive, then one wasn't using Abstract Base Classes correctly in the first place.

Erik Forbes
As the original question points out, abstract classes are certainly not obsolete. It is also true that there will be many cases where extension methods + interfaces provide a complete and better alternative to abstract classes.
Daniel Pratt
... I'm aware of that. I never said they couldn't be a better alternative - however I *do* say that if you employ this method, you're doing nothing other than using static methods to "extend" a class. Which in reality is *not* extension.
Erik Forbes
And thanks for the downvote...
Erik Forbes
Yeah, I felt bad about that, but it got me another badge, so it was worth it ;-)
Daniel Pratt
Grats - glad I could help out. =)
Erik Forbes
By the way, I voted you down because you gave the right answer to the wrong question. Had the question been "Do extension methods completely replace abstract classes?", my vote would've gone the other way.
Daniel Pratt
+1 for "[not] using Abstract Base Classes correctly..." People tend to avoid abstract base classes because they're done so wrong so often. Many less experienced devs must feel that wrong is the only way to do it after experiencing their first "framework." Have no fear noobs, it can be done right!
Michael Meadows
Daniel - how about my edit at the end?
Erik Forbes
I believe that there are *some* scenarios where in the past it would have made sense to implement concrete methods on abstract classes, but now, extension methods are the better alternative. If you don't agree, then we'll probably just have to agree to disagree.
Daniel Pratt
*shrugs* I suppose so. Interesting conversation nonetheless. =)
Erik Forbes
A: 

I think it depends on your use-

If your main concern is refactoring to minimize the number of source files and/or classes in an assembly, then yes, extension methods are definitely the way to go, and abstract classes will probably end up being used less.

However, for those who care more about what abstract classes represent conceptually, not much has changed. It still makes sense in a code-organizational context to put "public int getCalories()" in abstract class "Food", as it'd be silly for the person eating it (the code using a subclass of food) to define how many calories it has.

callingshotgun
A: 

In a word: Yes. Due to the fact that abstract classes impose a lot on future implementations, general advice seems to be to create abstract classes that implement interfaces (e.g. DBDataReader : IDataReader). So long as a method does not require access to the internal state of an object, I see no reason not to render it as an extension method. You get the functionality without the cost.

Daniel Pratt
I like your take.
BC
No, no you don't get the same functionality. This is a common misconception regarding extension methods. With his specific example you do, technically - but with abstract base classes you have access to internal private state that extension methods (being static methods) are still denied.
Erik Forbes
Where did I say that you get the same functionality? Please re-read the (last - 1) sentence of my answer.
Daniel Pratt
It's still not the same functionality - classes compiled without a reference to the extension method assembly cannot use the extension method (via reflection for instance), whereas if the base class had been modified they would.
Erik Forbes
Either I don't understand your point or you a grasping at straws. How often is a compiled class coded in such a way as to access methods added to a base class *after* the deriving class is compiled?
Daniel Pratt
I'm not grasping at anything. =) I'm simply pointing out that extension methods are *not* the same as instance methods added to a base class. Obviously you'd have to recompile your dependencies if you modified the base class...
Erik Forbes
All I'm saying is that if one believes that the existence of extension methods makes abstract base classes less attractive, then one wasn't using abstract base classes correctly in the first place.
Erik Forbes
In a world without extension methods, how would you implement IsCurrentUser (from the original question)?
Daniel Pratt
Well, as another poster mentioned, IsCurrentUser rings like a property - I would add an IsCurrentUser property to the interface definition and let implementers do their job and implement the property.
Erik Forbes
As far as defining a default implementation for IsCurrentUser - that's what abstract base classes are for.
Erik Forbes
And what if I have a user entity that already inherits some other class (EntityObject?)? You've just caused me a lot of heartache for no particularly good reason.
Daniel Pratt
Not much heartache if 'EntityObject' implements a property like IsCurrentUser - the great thing about having both interfaces and abstract base classes is that (if the hypothetical framework uses the interface) you can choose *not* to use the base class, and provide all your own implementation.
Erik Forbes
And that is one of the primary drawbacks of abstract classes: They are an all or nothing proposition. Already I have to implement IsCurrentUser twice, and what happens in your scenario when you need to add another operation to IUser?
Daniel Pratt
You don't have to implement IsCurrentUser twice - you implement it once, and your IUser.IsCurrentUser implementation simply returns the value of your EntityUser.IsCurrentUser property. -- Okay technically you implement it twice, but hey - this is OOP. =)
Erik Forbes
There are possibilities to avoid implementing twice: have the base classes share a common base, Create a Specification object for IsCurrentUser, and have both base classes use it.
Michael Meadows
Anyway, when the pain of using inheritance offsets the pain of adopting E methods, it's sometimes practical to adopt E methods. The cost is it's no longer polymorphic, and devs will have to know what namespace and dll to reference to get the behavior.
Michael Meadows
+1  A: 

Extension methods are nice, but you can't compare them or their usage to abstract classes. Don't forget what encapsulation is, it's one of the pillar of OOP...

ybo
+3  A: 

No, it will reduce some missuses of abstract classes.

An abstract class should contain default implementations/behaviors the subclasses can override. If factored appropriately, this means you could override just a single behavior of the class, and work with the defaults for the rest. Extension methods provide something really different to this.

eglasius
+4  A: 

What extension methods lets you do is to focus in on what abstract classes should actually be doing. There's a temptation to implement "utility" code in abstract classes because it will be used by implementers even though it may not be part of the logical inheritance tree. Extension methods let you attach these utility methods to the interface without cluttering up your abstract base classes.

EDIT

Specifically, I would apply these guidelines.

Inheritance

  • DO use inheritance if the behavior is part of the logical behavior of the base class
  • DO NOT use inheritance if the behavior is cross-cutting (applies to things outside of your object hierarchy). These will require duplication.

Utility Classes

  • DO use utility classes (static classes) if the behavior does not logically belong to the class it's acting on
  • DO NOT use utility classes if they modify the internal state of the object it's acting on. State modification should be reserved only for the object implementation hierarchy.

Extension Methods

  • DO use the same decision for extension methods as you would for utility classes when they create less friction. If adopting extension methods feels less natural, don't do it.
  • DO use extension methods to add utility to classes you don't have control over (like string).
  • DO NOT use extension methods when the behavior is consumed by the class it is extending. While it is possible to do it, it feels contrived
  • DO NOT use extension methods just because you can. In fact don't deviate from good old fashioned OOP unless you have to. When you have to, however, extension methods are a relatively uesful and harmless decision to make.

EDIT 2

Thought of another DO for extension methods

DO use extension methods to provide a natural language (internal DSL) for certain implementations. Here's a silly example.

int age = getAge();
if (age.IsDraftAge() && !age.IsLegalDrinkingAge())
{
    Console.WriteLine(@"You cannot drink until your birthdate on {0}.
Join the army instead.",
                      age.GetYearWhenGettingDrunkIsOk());
}
Michael Meadows
That sounds like a positive, but as you write more and more of your code in extension methods, you end up with what amounts to nothing more than static God classes.
Erik Forbes
It's a tradeoff. Putting utility code in your base classes prevents reusability, since these types of methods represent cross-cutting concerns. I'm only talking about making it easier to "do the right thing" and not put utility methods in base class implementations. I'll edit with an example.
Michael Meadows
No example, just guidelines.
Michael Meadows
Excellent list of guidelines - thanks =)
Erik Forbes
As for Edit 2 - great idea, although this *can* be taken too far.
Erik Forbes
A: 

I think there are absolutely cases where this is a good idea. Linq is a great example of the benefits, but there is another: streams.

The whole reason streams are an abstract class is because they had to support methods like BeginRead, ReadByte, etc. Stream could be an interface, and all of those methods could be extension methods instead. This would make it possible to do things like inherit from a non-stream class and add stream functionality, and make it (more) natural to add potentially useful stream methods like 'dump stream contents to memory buffer'.

Strilanc
A: 

If you don't need to access private fields from the extension method, then it's AFAIK the way to go, since you can inherit multiple interfaces and get all the related extensions this way (while you can only derive from a single abstract class).

Not sure what happens if extension method names collide, though?

Groo