Extension Methods in .NET - A Comment

J

Jon Skeet [C# MVP]

(It would really help if you'd get your newsreader to wrap at 76
characters, btw.)

Axel Dahmen said:
Exactly. Please refer to my reply below which comes without the
constructor call. Yet I'd prefer to have that constructor call. It
keeps the programmer bear in mind that a new object is being created.

Created unnecessarily, I would say. The extra type isn't adding any
value to the world except to expose the methods. Now you can expose the
methods which *effectively* you want to act on the original data, but
directly on that original data.

What genuine benefit is MyLinq giving, over extension methods? It adds
cruft when using LINQ, for no benefit.
Adding methods is in fact a kind of specialization.

Not to my mind. The point is that you're not saying that instances of
MyLinq are actually "special" in any way; it doesn't indicate anything
different about the data. It merely allows you to add the methods.

Extension methods give a different way of doing that, without using up
the one shot at inheritance. In fact, by not deriving from anything
your MyLinq now isn't specializing anything anyway, it's wrapping
something - again, for no reason.

On the fly no
other analogy comes to my mind than this, rather depicting, one:

A dog that is able to fly, say 100m, is a specialization of a standard
dog. No new property, just a new member function [myDog.fly(100);].
It's still a dog, but a special one... Having another, standard, dog
fly 100m by, say, using a catapult will not make that dog a
specialized one. It's still a standard dog that's flying. And people
should see that you're using a catapult to make him fly. And it
shouldn't be made too easy to use these catapults to make a normal
dog fly like a flying dog. Although both look the same while flying,
theresult, when they come down again in the end, will be different
when it comes to maintaining/debugging the dogs.

That's the thing though - extension methods lets you effectively give
"extra powers" to everything, precisely *because* you don't want to
limit it to particular implementations.
Well, you don't write "Math.Plus(a, b);", you write "a + b".

True, but you also don't write
new Math(1).Sin() which is *much* more akin to what you're doing.
So what's so ugly about writing "a.Sqrt(b);" ?

The fact that square root operates on a single number? There's no
logical reason to have two values involved.
These functions could
become members of INumber<T> or something which every number value
should implement. Operators are operators, no matter how they're
written.

Funnily enough, with extension methods you could make a.Sqrt() work
easily for all the built in numeric types (and any extras you wanted to
add).
You're absolutely right. I don't know about LinQ yet (that's why I
regretfully need to leave this thread in order to return learning)
and I copied the collection in my example. But please keep in mind
that I hacked it in in just two or three minutes. Just put the actual
LinQ Extension Method bodies in there and everything will be as with
LinQ which does all the same on the first Extension Method argument.

And it'll still be uglier than what we've got, IMO.
I'm looking forward to read into it!

Actually, as I just wrote, I regretfully need to leave this thread in
order to continue learning .NET 3.5. Perhaps I'll revisit it again
over the weekend, but that will be the final for me.

Thanks, Jon, for taking the time and arguing with me. Talking to you
is always a pleasure.

No problem - but I really think you ought to immerse yourself deeper in
future before dismissing things as awful.
 
A

Alex Clark

No, not at all. In my first .NET 1.0 I'd implemented an SqlHelper class
indeed. In my second (.NET 1.1) then I've encapsulated >SQL access into a
data access layer which didn't use any static methods at all. For string
formatting specific to data I'm dealing with >I'm using separate objects,
just as the .NET framework itself does. No, I can't remember having
implemented a static method for a >long time now.

So if for instance you have a requirement to apply a very specific series of
formatting operations on a string and return the result, and this
requirement exists at multiple points throughout your business logic tier,
what then? Your answer of "I'm using separate objects" is vague and
ambiguous. What kind of object implementation? Presumably it is instance
based as you avoid static methods of any kind? I'd like to know how you
would apply something simple like a specialised formatting to a string in
this case, because if you are genuinely instantiating a home-grown
formatting class just to avoid writing and calling a static method, I may
need to start looking out for your software projects on thedailywtf.com.

Yes. I'm programming since 1977. Rest assured I know VB. But have you ever
seen actual VB code? Have you seen anyone using >OOD? I didn't. Just
because VB offered so much procedural functionality. Just because it was
providing classes doesn't mean >people where using them.

Seen it? Check. Written it? Check. Maintained others' code? Check.
Rest assured *I* know VB, and in its latter incarnations prior to .NET there
wasn't a fat lot anyone could do with it other than "hello world" if you
wanted to avoid utilising classes.

VB6 and prior may only have implemented a fraction of a true objected
oriented framework, but it was more than just a little sideshow feature.
Yes, people were using classes.


In your original post you were implying that Extensions are more useful in
VB as "OOD is new there" and it is a procedural language. By definition you
could not have been referring to VB6 as Extension methods have never existed
in any pre-.NET version of VB.


Regards,
Alex
 
A

Alex Clark

So you want a specialised inherited class for everything in the framework
I'm not too deep into Linq, I'm discussing about Extension Methods here.
Yet, AFAIK, Linq only works on IEnumerable derived >classes. As does my
example... So what in fact would you do in both cases?

No, it does not. In your example you created a separate Linq wrapper
implementation for a Queue. Taking that one step further and assuming it
became Generic so as to work on any IEnumerable, it's still a wrapper class.
It does *not* provide the same non-breaking functionality that Linq
extensions do. The way MS have done it, List<T> is still List<T>. Queue<T>
is still Queue<T>, and so on. The only difference is that they offer up
some very powerful new features. They haven't broken any existing
implementations. I do not need to create pointless instances of specialised
wrapper classes.

Creating a wrapper class would be ugly and unncessary.

Using inheritance might actually work, except you'd have to create a new
sub-class of all existing classes in the framework that implement
IEnumerable<T>. Which then leads me back to my original question: what
happens when I want to create my own IEnumerable<T> type?

Again, I think this is a symptom of you not fully understanding the wheres
and whyfors of Extension methods. MS have (and have given us the capability
to) extended base classes and interfaces via Extension methods without
breaking existing code. Injecting new functions onto the IEnumerable type
means that they're available to any IEnumerable, and that the interface
itself remains unbroken. No need to alter code to handle breaking changes
due to base classes and interfaces that have been altered for new
functionality.

I agree with you. From the developer's point of view I don't see a
difference either (except for where to take functionality from, >where to
find it etc.), but from the designer's point of view Extension Methods are
a huge gate for proliferating bad coding.

As is object oriented design, in fact I would argue OO is far better
equipped for giving developers the opportunity to indulge in bad coding
practices and produce ridiculous implementations (going out of one's way to
avoid anything static and ensuring absolutely everything is instance-based,
for example). Extensions is, by comparison, a very small language shortcut.
I would compare Extensions to a blunted screw driver and OO to a buzz saw.
Give each one to a child and see which produces the most problems...


Actually you don't need to. As you've seen from my example I've used a
MyLinq generic to do the job. There wasn't even >inheritance involved here.
Still, in case you wouldn't need the derived class, just use the base
class. There is absolutely no reason >that would keep you from creating and
using base classes as long as they are not declared as being abstract.

Which requires further instantiation of a generic wrapper around an existing
IEnumerable<T> class, implicit/explicit casting, and less intuitive code.
Yuck, what a lot of work (and very ugly code) just for the sake of a half
dozen or so additional subroutines grafted on to existing classes. How is
that beneficial or easier for debugging purposes? In fact, as far as Linq
Extensions go, debugging is largely irrelevant as regardless of MS's
implementation the code would still be unavailable to you.

In a choice between having to instantiate special wrapper classes around any
of the IEnumerable's I use or just simply taking an existing
List/Queue/Array/etc and writing Linq queries, I know which one I'll choose,
and that it will be a lot easier to understand a year or two down the line
during maintenance.


Because, for instance, when implementing Extension Methods in a workgroup,
debugging will become a mess. You can't boil an >error down to a class's
implementation. It's impossible to narrow the search. You've just have to
debug the *whole* code.

Oh, that is a very weak and frankly ridiculous argument. For one, the
chances of you needing to extend your own code are far slimmer than say
providing an Extension method onto System.String. Example:

String myName = "Joe Bloggs";
String s = myName.ToPrettyFormat;

And your code crashes. Are you going to assume it's a bug in System.String,
or in your extension? I suppose that depends on how arrogant of a coder you
are, but I think the answer is obvious to most. Using today's debugging
tools (and yesterday's, and those of 7 years ago in fact) debugging
Extension methods is no more or less difficult than any other area of your
code. If I'm trying to find an error in a class, I'm going to be stepping
through code line-by-line in most instances anyway --- nothing about
Extensions makes my life any harder in that case. I really don't see your
problem, or to put it another way, I haven't encountered any challenges at
all with it.

I would prefer to have a set of
extension methods that are accessible via an instance of the object they
perform work on instead of some helper class.

Because it's sealed. Like System.String. Like many, many other types in
the .NET framework that are used heavily through a large nTier app.

Let's say for argument's sake I *can* drive from SqlConnection. I decide
that maybe there's some special work I want my code to do each time it
accesses a stored procedure, so I create SpecialSqlConnection and that
inherits from SqlConnection. I then implement my one function on that new
derived class. Simple eh?

I then go through and add the call to that new function in all areas of my
code that call out to stored procs. Except not only do I have to do that,
but I also have to change them to work with SpecialSqlConnection instead of
just SqlConnection. What if they received the connection object as a
parameter, passed down to them from the call stack? Whoops, looks like I've
got to trace all those calls back up the stacks until I've converted them to
use SpecialSqlConnection.

Yep, that's a nice easy solution, not at all complex, and would be a real
joy to debug, I'm sure...

Using Extension methods I can just "inject" my one new method onto the
existing sealed SqlConnection class, and voila, it works.

That's where it's being used, in my DAL. That does not mean that it isn't
being used extensively, and very regularly, and it certainly doesn't mean
that there aren't repetitive operations to be performed using the
SqlConnection class. It would not be appropriate for many of those sorts of
functions to be placed inside any other classes, and thus they end up in
their own class - one which would not require instantiating due to the
nature of the code it contains.

That's not to say I couldn't create a class that takes a SqlConnection as a
param to its constructor and has instance based methods that it performs on
that SqlConnection --- but why on earth would I waste time (not to mention
heap resources) on such an in-elegant and ill-thought out solution which
will inevitably result in much more hassle come debugging time? I'll keep
my Extensions thanks, and run the risk of the "paradigm police" knocking at
my door...

Alex
 
A

Axel Dahmen

(It would really help if you'd get your newsreader to wrap at 76
characters, btw.)

Strange... I'm using Windows Mail on Vista/W2k8. It wraps (my) text around smoothly... I've switched automatich line wrapping of to be able to provide sample code *without* extra wrapping.

Created unnecessarily, I would say. The extra type isn't adding any
value to the world except to expose the methods. Now you can expose the
methods which *effectively* you want to act on the original data, but
directly on that original data.
What genuine benefit is MyLinq giving, over extension methods? It adds
cruft when using LINQ, for no benefit.

Well, it adds a value to the world in that it's *obvious* for anyone in the workgroup where the functionality is actually coming from.

Not to my mind. The point is that you're not saying that instances of
MyLinq are actually "special" in any way; it doesn't indicate anything
different about the data. It merely allows you to add the methods.

And, here you see the advantage again: It's *not* the collection that provides anything. So one shouldn't write code *pretending* it provided anything. That's software engineering. It's not about how to create typing shortcuts at any cost, it's about clarity. That makes the distinction between a programmer and a software engineer. A programmer is only interested in clapping in code as quick (and dirty) as possible. That's his/her job. A software engineer is supposed to keep a look at keeping sources of functionality clear and obvious in code. So responsibilities can be quickly assigned and functionality can be quickly amended.

Extension methods give a different way of doing that, without using up
the one shot at inheritance. In fact, by not deriving from anything
your MyLinq now isn't specializing anything anyway, it's wrapping
something - again, for no reason.

That's because C# (in contrast to C++) doesn't allow for multiple inheritance or up-/downcasting. MyLinQ is just adding functionality to IEnumerable. So it would be sufficient to derive it from IEnumerable and to cast any IEnumerable to MyLinQ to have this functionality. But instead of adding this particular OOD functionality, MS invented Extension Methods.... boldly circumventing OOA, IMO.

That's the thing though - extension methods lets you effectively give
"extra powers" to everything, precisely *because* you don't want to
limit it to particular implementations.

Exactly, but to what price? The price of losing class responsibility. And thereby contradicting the most important OOA principle.

The fact that square root operates on a single number? There's no
logical reason to have two values involved.

Yes, sorry, my mistake. But giving a wrong example doesn't render the principle wrong. So it was "a.Sqrt();" then. Or "a.Power(b);".

Funnily enough, with extension methods you could make a.Sqrt() work
easily for all the built in numeric types (and any extras you wanted to
add).

Yes, speciously. Bot by no way truely. See above for my comment on the differences between a programmer's and a software engineer's point of view.

Regards,
Axel
 
A

Axel Dahmen

No, it does not. In your example you created a separate Linq wrapper
implementation for a Queue. Taking that one step further and assuming it
became Generic so as to work on any IEnumerable, it's still a wrapper class.
It does *not* provide the same non-breaking functionality that Linq
extensions do. The way MS have done it, List<T> is still List<T>. Queue<T>
is still Queue<T>, and so on. The only difference is that they offer up
some very powerful new features. They haven't broken any existing
implementations. I do not need to create pointless instances of specialised
wrapper classes.

I've created a new sample of how LinQ could have been implemented *generic*, *without* Extension Methods. And even implementing deferred execution. In fact it's actually the only feasibly way to implement LinQ. There is no other. I'll post that separately.

Creating a wrapper class would be ugly and unncessary.

No, I disagree. It wouldn't. It would be clear and obvious for anyone in the workgroup according the where the functionality is coming from. Not unnecessary at all when you're working in a workgroup. Please refer to my last reply to Jon here about the difference between a programmer's and a software engineer's point of view.

Using inheritance might actually work, except you'd have to create a new
sub-class of all existing classes in the framework that implement
IEnumerable<T>. Which then leads me back to my original question: what
happens when I want to create my own IEnumerable<T> type?

As I proved with my new example. MyLinq works on *any* IEnumerable.

MS have (and have given us the capability
to) extended base classes and interfaces via Extension methods without
breaking existing code.

No, they plainly have brought opportunities for cluttering up code responsibility.

Injecting new functions onto the IEnumerable type
means that they're available to any IEnumerable, and that the interface
itself remains unbroken.

Are you sure you really have understood OOD thoroughly? IEnumerable provides its interface and it still will. It's a classes task to either *implement* or *utilize* this functionality.

No need to alter code to handle breaking changes
due to base classes and interfaces that have been altered for new
functionality.

Again, it seems you didn't catch the original sample's idea. Don't just read the code, regard my argumentation as well and make your own considerations when reading a *sample* code. I didn't re-write LinQ in two minutes. Do I actually have to program *every* tiny thing out? Please refer to my new sample which just operates on IEnumerable.

As is object oriented design, in fact I would argue OO is far better
equipped for giving developers the opportunity to indulge in bad coding
practices and produce ridiculous implementations (going out of one's way to
avoid anything static and ensuring absolutely everything is instance-based,
for example). Extensions is, by comparison, a very small language shortcut.
I would compare Extensions to a blunted screw driver and OO to a buzz saw.
Give each one to a child and see which produces the most problems...

Good analogy. Though I'd rather compare Extension Methods to tape compared to OOD being good tools. Give both to a pro and see the difference.

Which requires further instantiation of a generic wrapper around an existing
IEnumerable<T> class, implicit/explicit casting, and less intuitive code.

What do you regard as being "intuitive"?? Intuitive can be easily read and understood by every other programmer in the workgroup. When actually using Extension Methods the first thing that'd come to everyone's mind would be "I didn't know this class provided such functionality... And its description doesn't say anything about it either. I'll guess I'll have to use 'go to definition' to see where that code comes from... - What the ...!!!" - Intuitive would mean "Ah, that's a MyLinq functionality, applied to IEnumerable. I know that..." Please note that I've been using MyLinq just for the sake of context here. Of course, everyone know's Linq functionality by now. But how about your own Extension Methods? NO ONE would know these. That about intuition...

Yuck, what a lot of work (and very ugly code) just for the sake of a half
dozen or so additional subroutines grafted on to existing classes.

You're so funny. That's the example LinQ compilation. What do you actually think does the original LinQ implementation look like? Did you actually think about that?

How is
that beneficial or easier for debugging purposes? In fact, as far as Linq
Extensions go, debugging is largely irrelevant as regardless of MS's
implementation the code would still be unavailable to you.

Er... You're distracting again from Extension Methods to LinQ, aren't you? Forgot it was just an example given to prove that LinQ could perfectly well have been implemented without using Extension Methods?

Oh, that is a very weak and frankly ridiculous argument. For one, the
chances of you needing to extend your own code are far slimmer than say
providing an Extension method onto System.String. Example:

String myName = "Joe Bloggs";
String s = myName.ToPrettyFormat;

And your code crashes. Are you going to assume it's a bug in System.String,
or in your extension? I suppose that depends on how arrogant of a coder you
are, but I think the answer is obvious to most.

Funny again... Just have a look at connect.microsoft.com and tell me again then, will you? You don't have to be arrogant to presume that an Assembly contains bugs. Who said only Microsoft does distribute Assemblies?

Using today's debugging
tools (and yesterday's, and those of 7 years ago in fact) debugging
Extension methods is no more or less difficult than any other area of your
code. If I'm trying to find an error in a class, I'm going to be stepping
through code line-by-line in most instances anyway --- nothing about
Extensions makes my life any harder in that case. I really don't see your
problem, or to put it another way, I haven't encountered any challenges at
all with it.

So you seem to have a lot of time for wasting it on debugging. I usually don't debug through the whole code but set a breakpoint to where I assume the bug to occur. - I'm also not reading a whole library to find information about Extension Methods. I'll go to the "Computer Science" department. You know, why? Because I assume it to be there. And nowhere else.

A function throwing an exception is not necessarily the source of an error. You might need to trace down an error reasonably much before the actual exception has occured.


Because it's sealed. Like System.String. Like many, many other types in
the .NET framework that are used heavily through a large nTier app.

So you should vote for removing the seal. Or add any required functionality to an appropriate functional class. You sure don't want to tell me that you want to add any special functionality to string? You sure have some functional class in your design which could provide this functionality in a discrete functional context. Don't you?

Let's say for argument's sake I *can* drive from SqlConnection. I decide
that maybe there's some special work I want my code to do each time it
accesses a stored procedure, so I create SpecialSqlConnection and that
inherits from SqlConnection. I then implement my one function on that new
derived class. Simple eh?

Yep... So far...

I then go through and add the call to that new function in all areas of my
code that call out to stored procs. Except not only do I have to do that,
but I also have to change them to work with SpecialSqlConnection instead of
just SqlConnection.

Er... you lost me here... No, honest... Wouldn't you have to do this with Extension Methods as well? AFAIK, the only reason for Extension Methods is to add methods, isn't it? Or does your code magically add these new function call to anywhere in your other code? Hmm...

What if they received the connection object as a
parameter, passed down to them from the call stack? Whoops, looks like I've
got to trace all those calls back up the stacks until I've converted them to
use SpecialSqlConnection.

Er... you lost me again... Going up a stack? What for? Didn't you just want to provide new functionality by creating SpecialSqlConnection?

Sorry, but your example stinks...

Regards,
Axel
 
A

Axel Dahmen

Seen it? Check. Written it? Check. Maintained others' code? Check.
Rest assured *I* know VB, and in its latter incarnations prior to .NET there
wasn't a fat lot anyone could do with it other than "hello world" if you
wanted to avoid utilising classes.

VB6 and prior may only have implemented a fraction of a true objected
oriented framework, but it was more than just a little sideshow feature.
Yes, people were using classes.


Yes, so-called "utility" and "helper" classes. Just collections of procedural code. That's not OOD at all.

Regards,
Axel Dahmen
 
A

Axel Dahmen

Hi Jon,
But there's still an extra class for no good purpose, which makes using
LINQ to Objects more tedious apart from the implicit conversions -
which you seem to think are *more* readable than extension methods.

Oh, and <T> isn't a type. Did you mean IEnumerable<T>?

I wrote MyLinq<T> said:
No, just implicit conversions, invalid syntax, and still not fixing the
deferred and streaming issues.

I've now created another, more elaborated, working example, fixing all those issues. It even provides deferred execution. Please note that the last few lines are exactly like LinQ, except for the new MyLinq(). Which no one really is going to regard as being too much of an effort, I presume.

And yes, Alex, it still makes use of Queue. Hey, it's just an example. If you like you may make it generic. Be my guest.

Anyway, it proves that LinQ (and ANYTHING else) could have been perfectly well implemented without introducing and using Extension Methods:

----------------------------------------------

using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;

namespace MyLinqTest
{
/// <summary>
/// This class would have been implemented by Microsoft.
/// </summary>
/// <typeparam name="T">
/// Type to be dealt with.
/// </typeparam>
public class MyLinq<T> : IEnumerable<T>
{
private IEnumerable<T> _collection;
private Func<T, bool> _where;


public MyLinq(IEnumerable<T> coll)
{
_collection = coll;
}

public MyLinq<T> Where(Func<T, bool> predicate)
{
_where = predicate;

return this;
}

public MyLinq<TResult> Select<TResult>(Func<T, TResult> selector)
{
Queue<TResult> retVal = new Queue<TResult>();

foreach (T elem in _collection) if (_where(elem)) retVal.Enqueue(selector(elem));

return new MyLinq<TResult>(retVal);
}

public MyLinq<TResult> SelectMany<TResult>(Func<T, TResult> selector)
{
Queue<TResult> retVal = new Queue<TResult>();

foreach (T elem in _collection) if (_where(elem)) retVal.Enqueue(selector(elem));

return new MyLinq<TResult>(retVal);
}

#region IEnumerable<T> Member

public IEnumerator<T> GetEnumerator()
{
return _collection.GetEnumerator();
}

#endregion

#region IEnumerable Member

IEnumerator IEnumerable.GetEnumerator()
{
return _collection.GetEnumerator();
}

#endregion
}

internal class Program
{
static internal void Main(string[] args)
{
List<string> persons = new List<string> { "Hans", "Fritz", "Hermine" };

MyLinq<string> filteredPersons = new MyLinq<string>(persons).Where(p => p == "Fritz").Select(p => p);

foreach (string name in filteredPersons) Console.WriteLine(name);

while (!Console.KeyAvailable) Thread.Sleep(500);
}
}
}
 
M

Marc Gravell

I'm really not sure that binding to a concrete implementation (MyLinq)
rather than the abstract interface is a great move; it might work for
delegate-based (LINQ-to-objects) work, but it gets very tricky when you
start looking at expression-based work - as you have the joy of trying
to resolve the members at the provider level.

Personally (and this matches most else of what I hear) I think extension
methods are a very clean solution to this and a *range* of other related
problems; not just LINQ. All extensions do is provide simple (and
intellisense explorable) access to static utility methods. They get my
full blessing. If you don't like them, don't use them - but I reckon
your throwing your toys a bit here...

Marc
 
A

Alex Clark

Yes, so-called "utility" and "helper" classes. Just collections of
No, instance classes, not static/shared code. I suggest you actually learn
a bit about VB6 before coming up with your next response.

Who am I kidding, apparently you know all languages of all code better than
anyone on here; far be it from me to contradict you, so I'll leave you to
your paradigm-perfect world where all problems are nails and your OOD,
static-less implementations are the only hammer.

*sigh* some of the uninformed children on this newsgroup just makes me
shudder sometimes.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top