.NET Forum / .NET Framework / New Users / April 2008
Extension Methods in .NET - A Comment
|
|
Thread rating:  |
Axel Dahmen - 29 Mar 2008 23:21 GMT I've just read into Extension Methods in .NET and can't hold to give a short comment on them:
Using static classes to purely use another class's fields and methods to even pretend being a member of that other class without actually being a member of that class is very hard to understand. It compromises any refacturing effort. Who invents such things...?
OOD/OOA in mind, to me Extension Methods seem to be the virtually dirtiest workaround for circumventing multiple inheritance I've seen so far.
Extension Methods in .NET is a slap in the face of all serious software engineers.
www.axeldahmen.com Axel Dahmen
Jon Skeet [C# MVP] - 29 Mar 2008 23:39 GMT > I've just read into Extension Methods in .NET and can't hold to give > a short comment on them: [quoted text clipped - 10 lines] > Extension Methods in .NET is a slap in the face of all serious > software engineers. Personally, I think they're great - when used appropriately.
They can greatly enhance the readability of code, and LINQ is a great example. Which do you think is clearer:
1) Without extension methods:
IEnumerable<string> names = Enumerable.Select( (Enumerable.Where(people, person => person.Age > 17), person => person.Name);
or
IEnumerable<string> names = people.Where(person => person.Age > 17) .Select(person => person.Name);
?
The latter gives a much clearer indication of the order in which the transformations will take place, as well as being more concise.
Yes, extension methods can be abused. However, they allow a lot of really *nice* uses too - and enriching interfaces (as LINQ does) is probably the best use going.
Of course, you can avoid using them yourself - but personally I'll use them (sparingly) to write more readable, maintainable code.
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk
Axel Dahmen - 30 Mar 2008 02:14 GMT Hi Jon,
thanks for your reply.
How about keeping the better syntax but without Extension Methods?
As far as I can see, a generic could have done the trick here:
Linq<People> people;
IEnumerable<string> names = people.Where(person => person.Age > 17) .Select(person => person.Name);
Regards, Axel Dahmen
Jon Skeet [C# MVP] - 30 Mar 2008 07:45 GMT > thanks for your reply. > [quoted text clipped - 6 lines] > IEnumerable<string> names = people.Where(person => person.Age > 17) > .Select(person => person.Name); That only works if you start with a Linq<People> - it won't work on all the many existing enumerable collections. It also forces each of those methods to expose that they're returning a Linq<People> as well.
Being able to operate on arbitrary IEnumerable<T> is very, very useful - and you can apply the same technique to other interfaces.
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk
Peter Duniho - 29 Mar 2008 23:42 GMT > [...] > Extension Methods in .NET is a slap in the face of all serious software > engineers. You're welcome to your opinion, even if you cannot be bothered to express it in a polite, respectful way. Nevertheless, suffice to say your opinion is just that: merely your opinion. Many people can and do disagree.
One particular example: much of what LINQ provides would not work without extension methods. It relies on it heavily.
But regardless, no one's forcing you to use them. If you don't like them, then don't use them.
Pete
Axel Dahmen - 30 Mar 2008 02:26 GMT Hi Peter,
> You're welcome to your opinion, even if you cannot be bothered to express > it in a polite, respectful way. Nevertheless, suffice to say your opinion > is just that: merely your opinion. Many people can and do disagree. You're right. It's not one of my strengths to be eloquent when I see a bad design decision. I apologize for that. I'd like to hear opinions of those who disagree. Particularly how they want to explain Extension Methods in OOD terms. How can someone possibly argue about keeping an objects methods within the object (a typical OOD pattern) while at the same time accepting Extension Methods?
> One particular example: much of what LINQ provides would not work without > extension methods. It relies on it heavily. I guess so. That's just why they invented it. There's not other possible reason for it that I could think of... Still it's a wrong approach. The same Linq syntax could have been achieved with other, more OOD, practices.
> But regardless, no one's forcing you to use them. If you don't like them, > then don't use them. You got me wrong, I'm afraid. My argument is not about using them. It's about arguing with colleagues about using them. If I tell them to keep member functions within a class instead of creating some function anywhere, providing an object as a parameter, doing nothing else than to handle the object's properties, what will they say? "Must be a valid pattern. MS and millions of others are using it!" How am I (or any other Software Engineer) supposed to argument on this?
Regards, Axel Dahmen
Peter Duniho - 30 Mar 2008 02:36 GMT > [...] > You got me wrong, I'm afraid. My argument is not about using them. It's > about arguing with colleagues about using them. If I tell them to keep > member functions within a class instead of creating some function > anywhere, providing an object as a parameter, doing nothing else than to > handle the object's properties, what will they say? Rather than the contrived response you attribute to them, I would guess that they would (gently, you hope) explain to you that extension methods are NOT a "member function" of the class being extended.
If they were, they'd have access to the class's private and protected members, which they don't.
Extension methods are little more than a syntactic shorthand for writing a method that takes an instance of some class and performs some operation using that instance, using only the public members that'd be available to any other non-member method. People are already writing exactly that kind of method on a regular basis. All that extension methods do is make the code that uses that technique more concise.
As Gregory said, you would have more credibility as a detractor of extension methods if you appeared to be coming from an informed position. Right now, you certainly don't seem to be.
Pete
Axel Dahmen - 30 Mar 2008 03:11 GMT Thanks Peter,
you are right. I should get more into Linq before arguing. In fact, I'm not arguing against Linq or its syntax, but against Extension Methods themselves. I'm quite confident that Linq could have been as gracefully been implemented without the invention of Extension Methods. If a pattern like Extension Methods are used on a wide bases, as you wrote, then programmers should ask themselves if they shouldn't move these methods into the objects' class definition itself (http://www.refactoring.com/catalog/moveMethod.html).
Regards, Axel Dahmen
---------------------
>> [...] >> You got me wrong, I'm afraid. My argument is not about using them. It's [quoted text clipped - 22 lines] > > Pete Peter Duniho - 30 Mar 2008 04:15 GMT > Thanks Peter, > > you are right. I should get more into Linq before arguing. That's not what I wrote.
> In fact, I'm not arguing against Linq or its syntax, but against > Extension Methods themselves. I know. And based on what you've written here, it really doesn't seem as though you understand what extension methods do.
> I'm quite confident that Linq could have been as gracefully been > implemented without the invention of Extension Methods. I'm not convinced. Perhaps you could post a valid, complete example of what you mean. Certainly the other example isn't nearly as graceful as using extension methods would be, given that you'd have to wrap some existing class in the generic class you seem to be proposing in order for it to work as the code you posted shows.
> If a pattern like Extension Methods are used on a wide bases, as you > wrote, then programmers should ask themselves if they shouldn't move > these methods into the objects' class definition itself They can ask that all they want. If they are dealing with a class that they don't own, that's simply not possible. And if they are dealing with a class that's sealed, they cannot even sub-class the class in order to add the method. And even if they can sub-class the class, that would require instantiating the sub-class in order to call the method on the class.
In other words, extension methods are addressing a very specific scenario, one that is not addressable at all by the alternative you propose as superior.
The fact is, it does not break OOP principles to have a static method that takes as a parameter an instance of some other class and does something with that instance. People have been writing that kind of code in OOP languages since OOP languages have been around. And that's all that an extension method is, except with a syntax that is more concise.
As Jon already pointed out, it's not like people should be going around using extension methods willy nilly. And of course, as is the case with all language conveniences that have been present since programmers moved past writing their code as individual ones and zeroes, it's important to understand the nature of what one is writing. For example, if you use the LINQ extension method Count() on an IEnumerable<T> instance, you need to understand that IEnumerable<T> does not itself offer a direct access to the count of elements, and thus there could be significant overhead to counting an enumerable class.
But none of that suggests that extension methods are in any way flawed, and certainly not that they are a "slap" in anyone's face. It just means that you have something new to learn if you expect to be proficient in the latest .NET technologies.
Frankly, all of the complaints in your original post -- that extension methods in some way "pretend" to be a member of another class (they don't do any such thing...they simply use an instance of another class as any other code not in that class could use it), that it compromises any "refacturing [sic]" effort (did you mean refactoring? in any case, it doesn't prevent refactoring at all), that they are a workaround for circumventing multiple inheritance (extension methods have nothing to do with multiple inheritance), and your most profane assertion that they are a "slap in the face of all serious software engineers" (really? I don't feel slapped...are you telling me I'm not a serious software engineer?) -- are without merit.
Whether you and your coworkers wind up writing your own extension methods is a matter of your own internal discussions. Certainly if one is going to use them, there ought to be a good reason for it. I rarely have code that could benefit from the use of extension methods. But to rant against them as you have, especially when you don't appear to really understand what they do in the first place, all that's going to do is cause needless friction between you and other programmers.
It may well still be fashionable for programmers to carry themselves with such anti-social attitudes, but I can assure you that it's not likely to be a positive contribution to your career to act that way. If you're going to argue against extension methods, at least learn enough about them so that you have arguments against them that make some sense.
Pete
Axel Dahmen - 31 Mar 2008 06:52 GMT >> In fact, I'm not arguing against Linq or its syntax, but against >> Extension Methods themselves. > > I know. And based on what you've written here, it really doesn't seem as > though you understand what extension methods do. Believe me, I did.
>> I'm quite confident that Linq could have been as gracefully been >> implemented without the invention of Extension Methods. > > I'm not convinced. Perhaps you could post a valid, complete example of > what you mean. Sure, here's is a simple example. I've nailed it together in a couple of minutes so don't look too closely. Yet it does the job:
- MyLinq.cs (this is a sample Linq implementation) ---------------------------------------------------------------------------- using System.Collections; using System.Collections.Generic;
namespace LinqTest { class MyLinq<T> where T:class { private Queue<T> _coll;
public MyLinq(Queue<T> coll) { _coll = coll; }
public int Count() { int retVal = 0;
foreach (T o in _coll) ++retVal;
return retVal; }
public MyLinq<T> Select() { Queue<T> retVal=new Queue<T>();
foreach(T o in _coll) retVal.Enqueue(o);
return new MyLinq<T>(retVal); } } } -----------------------------------------------------------------------------
- Person.cs ---------------------------------------------------------------------------- namespace LinqTest { class Person { public string FirstName { get; set; } public string LastName { get; set; } } } -----------------------------------------------------------------------------
- Program.cs ---------------------------------------------------------------------------- using System; using System.Collections.Generic;
namespace LinqTest { class Program { static void Main(string[] args) { Queue<Person> persons = new Queue<Person>(); persons.Enqueue(new Person { FirstName = "Peter", LastName = "Ustinov" }); persons.Enqueue(new Person { FirstName = "Bart", LastName = "Simpson" });
MyLinq<Person> linq = new MyLinq<Person>(persons);
Console.WriteLine(linq.Select().Count()); } } }
-----------------------------------------------------------------------------
The last line is the most important as it looks almost exactly like Linq, but it has been implemented in an object oriented fashion.
> Certainly the other example isn't nearly as graceful as > using extension methods would be, given that you'd have to wrap some > existing class in the generic class you seem to be proposing in order for > it to work as the code you posted shows. I don't see a difference..... Where do you see it?
> And if they are dealing with > a class that's sealed, they cannot even sub-class the class in order to > add the method. That's why it's sealed. What did you think?? When someone says "Turn right here!" are you turning left then?
> And even if they can sub-class the class, that would > require instantiating the sub-class in order to call the method on the > class. There's no point in what you're saying. The concept of Expansion Methods isn't magic. You need to instanciate an object to use methods on it there as well.
> In other words, extension methods are addressing a very specific scenario, > one that is not addressable at all by the alternative you propose as > superior. Yes, a scenario like "no rules".
> The fact is, it does not break OOP principles to have a static method that > takes as a parameter an instance of some other class and does something > with that instance. People have been writing that kind of code in OOP > languages since OOP languages have been around. And that's all that an > extension method is, except with a syntax that is more concise. I agree with you here. But there is a very tiny area where they should be used. Creating polymorphic factories, for example. Anything else is usually procedural code dressed as OOD.
> For example, if you use the > LINQ extension method Count() on an IEnumerable<T> instance, you need to > understand that IEnumerable<T> does not itself offer a direct access to > the count of elements, and thus there could be significant overhead to > counting an enumerable class. So where's your point? I've added a Count() property to my above example.
> extension > methods in some way "pretend" to be a member of another class (they don't > do any such thing...they simply use an instance of another class as any > other code not in that class could use it), Apparently you didn't understand Expansion Methods. In fact the only purpose of them is in fact to pretend to be a member of another class. Anything else can be done without this new syntax. You don't need Expansion Methods to implement static methods that interact on other objects. But you need Expansion Methods to syntactically pretend these static methods would belong to another object.
> that it compromises any > "refacturing [sic]" effort (did you mean refactoring? in any case, it > doesn't prevent refactoring at all), Found a typo? Cool... you may keep it.
I disagree. The concept of Expansion Methods contradict any refactoring efforts. It compromises the "Move Method" paradigm.
Regards, Axel Dahmen
Rory Becker - 31 Mar 2008 08:57 GMT Hello Axel,
> And if they are dealing with a class that's sealed, they cannot even > sub-class the class in order to add the method. > > That's why it's sealed. What did you think?? When someone says "Turn > right here!" are you turning left then? IMHO... Sealing a class has less to do with stopping you inheriting from it and more to do with ensuring that someone doesn't fundamentally alter the way it works and breaking methods that depend on params of that type.
For example if you could inherit from string you would be able to create a derived string that fundamentally broke the internasl of it and would still be passable to methods that required a string.
Extension methods don't give you anything like this level of access, but allow you to enhance the the string class additively.
This is not a bad thing.
-- Ror
Axel Dahmen - 03 Apr 2008 07:28 GMT Hi Rory,
> IMHO... Sealing a class has less to do with stopping you inheriting from > it and more to do with ensuring that someone doesn't fundamentally alter [quoted text clipped - 3 lines] > a derived string that fundamentally broke the internasl of it and would still > be passable to methods that required a string. That would only be possible if string provided virtual methods to be overridden. And this again would be a deliberate design decision. If string provided virtual methods then they are supposed to be overridden. And overriding shouldn't break a class. If it did then it's a design flaw of the class.
Usually to prevent overriding methods from breaking base class code, the base class methods are *not* marked virtual but call an empty virtual method instead, like:
private void MustExecute() { // do necessary stuff ...
CanOverride(); }
public virtual void CanOverride() {}
Axel
Jon Skeet [C# MVP] - 31 Mar 2008 09:10 GMT > >> In fact, I'm not arguing against Linq or its syntax, but against > >> Extension Methods themselves. [quoted text clipped - 12 lines] > Sure, here's is a simple example. I've nailed it together in a couple of > minutes so don't look too closely. Yet it does the job: <snip>
It does the job if you don't mind the fact that it copies all the data. If I write:
someData.Where(firstCondition) .Where(secondCondition) .OrderBy(firstOrdering) .ThenBy(secondOrdering) .Select(projection)
then I only want one item of data to be copied at a time. Your implementation breaks that completely.
I think you have missed some of the fundamental points of LINQ to Objects.
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk
Axel Dahmen - 03 Apr 2008 07:33 GMT > someData.Where(firstCondition) > .Where(secondCondition) [quoted text clipped - 4 lines] > then I only want one item of data to be copied at a time. Your > implementation breaks that completely. No, why should it? In fact, it does nothing else Linq does. How do you think Linq is implemented? Probably the method examples I gave weren't optimized but that doesn't make them basically different from Linq.
Again, Linq is no magic. Extension Methods makes it look magic, but it isn't.
Axel
Jon Skeet [C# MVP] - 03 Apr 2008 08:05 GMT > > someData.Where(firstCondition) > > .Where(secondCondition) [quoted text clipped - 9 lines] > weren't optimized but that doesn't make them basically different from > Linq. They are *fundamentally* different from LINQ.
> Again, Linq is no magic. Extension Methods makes it look magic, but > it isn't. Look at what your code does.
public MyLinq<T> Select() { Queue<T> retVal=new Queue<T>();
foreach(T o in _coll) retVal.Enqueue(o);
return new MyLinq<T>(retVal); }
What would happen if you passed an infinite sequence into that? LINQ would handle it absolutely fine. Your code wouldn't.
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk
Axel Dahmen - 03 Apr 2008 09:04 GMT > What would happen if you passed an infinite sequence into that? LINQ > would handle it absolutely fine. Your code wouldn't. Wow, you're quick... ;)
Are we still discussing Extension Methods here? Or are we discussing LinQ? I'm still sure that everything Extension Methods did to LinQ could have been accomplished without them as gracefully.
Regards, Axel Dahmen
Jon Skeet [C# MVP] - 03 Apr 2008 09:41 GMT > > What would happen if you passed an infinite sequence into that? LINQ > > would handle it absolutely fine. Your code wouldn't. [quoted text clipped - 4 lines] > LinQ? I'm still sure that everything Extension Methods did to LinQ > could have been accomplished without them as gracefully. Without extension methods (and without actually putting all the LINQ query operators as part of IEnumerable<T> itself, which would be a crazy burden on implementors) you couldn't write:
mySource.Where(x => x.Length > 5) .Select(x.ToUpper())
(and all the other query operators, of course)
with mySource as any of:
Stack<string> string[] List<string> or basically *any* IEnumerable<string>
The ability to work on *any* IEnumerable<T> without having to create an intermediate wrapper class or something similar is part of the elegance of LINQ in my view.
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk
Axel Dahmen - 04 Apr 2008 21:17 GMT > Without extension methods (and without actually putting all the LINQ > query operators as part of IEnumerable<T> itself, which would be a [quoted text clipped - 15 lines] > intermediate wrapper class or something similar is part of the elegance > of LINQ in my view. Frankly, I don't see a difference to my example, where you just would had to write:
myLinq.Where(x => x.Length > 5) .Select(x.ToUpper())
No IEnumerable<T> extension, no wrapper class. Just a new kind of collection class (MyLinq). Did you have a chance to look at my example? Of course, I didn't implement delegates as method parameters. I was just a quick example. But implementing that would be an easy exercise. And it would have been done my MS, not us.
Regards, Axel Dahmen
Jon Skeet [C# MVP] - 04 Apr 2008 21:35 GMT > > The ability to work on *any* IEnumerable<T> without having to create an > > intermediate wrapper class or something similar is part of the elegance [quoted text clipped - 7 lines] > No IEnumerable<T> extension, no wrapper class. Just a new kind of > collection class (MyLinq). But *every* time I want to use LINQ, I then have to create an instance of MyLinq - which is adding no value to me. It's just letting me call a bunch of methods to act on any IEnumerable<T>. Well guess what extension methods are doing... transparently.
Adding an extra piece of inheritance without actual specialization doesn't add any value, just complexity in my view. You're just hiding *effectively* static methods behind instance methods.
Would you be happier if the Math class had to be instantiated each time you used it, too?
> Did you have a chance to look at my > example? I looked at your example which copied all the data every time, instead of streaming it. Do you have another one? Of course, it's possible to wrap that behaviour as well, but I do think the fact that you don't grasp the streaming and deferred nature of LINQ as being important shows that you're not really tuned into it yet.
> Of course, I didn't implement delegates as method > parameters. I was just a quick example. But implementing that would > be an easy exercise. And it would have been done my MS, not us. Actually, LINQ to Objects is pretty straightforward to implement for the most part - certainly if you don't need a particularly efficient OrderBy algorithm, for example.
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk
Axel Dahmen - 04 Apr 2008 23:01 GMT > But *every* time I want to use LINQ, I then have to create an instance > of MyLinq - which is adding no value to me. It's just letting me call a > bunch of methods to act on any IEnumerable<T>. Well guess what > extension methods are doing... transparently. 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. For subsequent calls the object should be cached.
> Adding an extra piece of inheritance without actual specialization > doesn't add any value, just complexity in my view. You're just hiding > *effectively* static methods behind instance methods. Adding methods is in fact a kind of specialization. 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, the result, when they come down again in the end, will be different when it comes to maintaining/debugging the dogs.
> Would you be happier if the Math class had to be instantiated each time > you used it, too? Well, you don't write "Math.Plus(a, b);", you write "a + b". So what's so ugly about writing "a.Sqrt(b);" ? 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.
> I looked at your example which copied all the data every time, instead > of streaming it. Do you have another one? Of course, it's possible to > wrap that behaviour as well, but I do think the fact that you don't > grasp the streaming and deferred nature of LINQ as being important > shows that you're not really tuned into it yet. 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.
> Actually, LINQ to Objects is pretty straightforward to implement for > the most part - certainly if you don't need a particularly efficient > OrderBy algorithm, for example. 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.
Best regards, www.axeldahmen.com Axel Dahmen
Jon Skeet [C# MVP] - 04 Apr 2008 23:15 GMT (It would really help if you'd get your newsreader to wrap at 76 characters, btw.)
> > But *every* time I want to use LINQ, I then have to create an instance > > of MyLinq - which is adding no value to me. It's just letting me call a [quoted text clipped - 4 lines] > 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 an extra piece of inheritance without actual specialization > > doesn't add any value, just complexity in my view. You're just hiding > > *effectively* static methods behind instance methods. > > 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: > [quoted text clipped - 8 lines] > 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.
> > Would you be happier if the Math class had to be instantiated each time > > you used it, too? > > 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).
> > I looked at your example which copied all the data every time, instead > > of streaming it. Do you have another one? Of course, it's possible to [quoted text clipped - 8 lines] > 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.
> > Actually, LINQ to Objects is pretty straightforward to implement for > > the most part - certainly if you don't need a particularly efficient [quoted text clipped - 8 lines] > 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.
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk
Axel Dahmen - 08 Apr 2008 07:57 GMT > (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.
>> 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. 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.
>> 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. 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
Peter Duniho - 31 Mar 2008 12:07 GMT It seems to me that the whole discussion boils down to this:
> [...] >> The fact is, it does not break OOP principles to have a static method [quoted text clipped - 6 lines] > I agree with you here. But there is a very tiny area where they should > be used. No one has suggested extension methods be used except in the very specific scenario I describe above. They in fact CANNOT BE USED IN ANY OTHER SCENARIO. And you have specifically written here that in that scenario -- THE ONLY ONE IN WHICH EXTENSION METHODS CAN BE USED -- you agree with me. So what's your problem?
Given the above, the only possible way you could have a disagreement with the use of extension methods is for you to not understand them. Because you've specifically stated that you agree with the one thing that extension methods do. There's nothing left to disagree with, except things you've imagined extension methods do but which they don't.
Regardless, here's the bottom line: extension methods are here to stay. You are welcome to not use them, but you will have to accept the fact that your anti-extension method attitude puts you in a very tiny minority. If you want to spend the rest of your career debating the issue with others, that's your choice. But it's really a waste of your time. You'd be much better off just finding a new job where you don't have to worry about using them.
In any case, you've established very well in this thread that you don't understand extension methods. If and when you're willing to accept that fact, then it might be productive to continue the conversation. Until such time however, it's obviously a waste of time to try to discuss the issue with you. It's impossible to find any common ground from which to debate the finer points as long as you continue to invent things that aren't true about extension methods in your pursuit of criticism of them.
Pete
Axel Dahmen - 03 Apr 2008 07:36 GMT >>> The fact is, it does not break OOP principles to have a static method >>> that [quoted text clipped - 11 lines] > THE ONLY ONE IN WHICH EXTENSION METHODS CAN BE USED -- you agree with me. > So what's your problem? No, I didn't agree on using Extension Methods. I agreed on the fact that static methods take other objects as parameters. In fact, every function having parameters does that.
Stop flaming!
Axel
Alex Clark - 31 Mar 2008 20:32 GMT Axel,
Sure, here's is a simple example. I've nailed it together in a couple of minutes so don't look too closely. Yet it does the job: </snip> The last line is the most important as it looks almost exactly like Linq, but it has been implemented in an object oriented fashion.
So you want a specialised inherited class for everything in the framework that implements IEnumerable? What happens when I create my own IEnumerable class and I want that to provide me with LINQ services, what do I do then?
Why incur the overhead of inheritance for each and every collection-based class (which oftentimes need to provide the best performance and lowest working set possible) when a set of extension functions would do the same job?
You are arguing that it *must* be this way in order for it to truly support the OOD paradigm, and that only inheritance can do that. But OOD is as much about coding *against* the classes you create as it is about creating them in the first place. As a developer, I'm less fussed as to whether List<T> truly inherits from some sort of Linq base type or if it has a series of extension functions grafted onto it, particularly if the code is identical. Where I will start to get bothered is when I find that the List<T> type is not strictly the same type as it used to be, requiring me to alter dependencies on it. Or where its performance has suffered due to MS adding another layer into the inheritance hierarchy.
One of the most important rules of OOD is to use it as intended. You don't insert a screw into wood with a hammer, so why would you demand an inherited sub-type of List<T> when that sub type would only add some new functionality (a half dozen new functions) rather than override base behaviour? It is simply not necessary, it creates maintenance problems, duplicated code, and adds performance overhead.
> And if they are dealing with > a class that's sealed, they cannot even sub-class the class in order to > add the method. That's why it's sealed. What did you think?? When someone says "Turn right here!" are you turning left then?
If I seal a class, I don't want anybody to override its internal behaviour, and that is the only condition for sealing it. I would have no problem with anybody adding functionality to it that did *not* interfere with its behaviour, in the same way that I would have no problem with somebody writing a utility class that accepted my class as a parameter and performed work with it. In fact, I just described Extension methods right there --- syntactical sugar.
I agree with you here. But there is a very tiny area where they should be used. Creating polymorphic factories, for example. Anything else is usually procedural code dressed as OOD.
Perhaps so, but why is that such a problem? 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. It's more intuitive, it's easier to maintain, and a heck of a lot less clumsy. Is my "CheckTablePermissions" routine in my SecurityHelper class or my SqlHelper class? Neither, it's a method on the SqlConnection class. Much easier and much more elegant. I don't agree with the paradigm-breaking nature of it? I don't use it. Simple as.
I disagree. The concept of Expansion Methods contradict any refactoring efforts. It compromises the "Move Method" paradigm.
In what way?
Regards, Alex
Axel Dahmen - 03 Apr 2008 08:07 GMT > So you want a specialised inherited class for everything in the framework > that implements IEnumerable? What happens when I create my own IEnumerable > class and I want that to provide me with LINQ services, what do I do then? 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?
> As a developer, I'm less fussed as to whether List<T> > truly inherits from some sort of Linq base type or if it has a series of > extension functions grafted onto it, particularly if the code is identical. 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.
> Or where its performance has suffered due to MS adding > another layer into the inheritance hierarchy. Just want to say that adding layers of hierarchy doesn't necessarily lack performance. Basically additional code is only executed in constructors (and destructors). But - apart from any additional code being executed - it's not more than just a function call to the base class's constructor/destructor. Anything else would have been executed as well by using any other possible concept in the world.
> One of the most important rules of OOD is to use it as intended. You don't > insert a screw into wood with a hammer, so why would you demand an inherited > sub-type of List<T> when that sub type would only add some new functionality > (a half dozen new functions) rather than override base behaviour? It is > simply not necessary, it creates maintenance problems, duplicated code, and > adds performance overhead. 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.
> If I seal a class, I don't want anybody to override its internal behaviour, > and that is the only condition for sealing it. I would have no problem with > anybody adding functionality to it that did *not* interfere with its > behaviour, Please refer to my other reply where I gave an example of how to keep internal behaviour solid without sealing a class.
> in the same way that I would have no problem with somebody > writing a utility class that accepted my class as a parameter and performed > work with it. In fact, I just described Extension methods right there --- > syntactical sugar. Yep, syntactical sugar for having ignored OOA. My humble opinion still.
> Perhaps so, but why is that such a problem? 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.
> 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. Helper classes are usually a good example for procedural code disguised as OOD. I'd regard any such as bad. They don't help. I can't discuss with you on your example without having seen your code. But if you'd like to add a function to SqlConnection then why don't you just create a derivate class then? Or why are you using it so massively at all? It's a technical class that should be hidden somewhere in a data access layer class hierarchy.
Axel
Jon Skeet [C# MVP] - 03 Apr 2008 09:00 GMT > > So you want a specialised inherited class for everything in the framework > > that implements IEnumerable? What happens when I create my own IEnumerable [quoted text clipped - 3 lines] > here. Yet, AFAIK, Linq only works on IEnumerable derived classes. As > does my example... So what in fact would you do in both cases? LINQ to Object only works on IEnumerable<T> (and IEnumerable to some extent) but LINQ itself is completely type-agnostic. For example, Marc Gravell and I recently wrote a "push" version of LINQ by implementing the same set of operators as extensions on a different interface.
> > As a developer, I'm less fussed as to whether List<T> > > truly inherits from some sort of Linq base type or if it has a series of [quoted text clipped - 4 lines] > to find it etc.), but from the designer's point of view Extension > Methods are a huge gate for proliferating bad coding. Do you really not see any benefit in being able to effectively add behaviour to interfaces without the interface implementor having to do any work themselves?
> > Or where its performance has suffered due to MS adding > > another layer into the inheritance hierarchy. [quoted text clipped - 5 lines] > class's constructor/destructor. Anything else would have been > executed as well by using any other possible concept in the world. Well, virtual methods can't be inlined of course. I agree it's not likely to be significant in many cases. Personally I find inheritance has more of a *design* penalty than a *performance* penalty.
> > One of the most important rules of OOD is to use it as intended. You don't > > insert a screw into wood with a hammer, so why would you demand an inherited [quoted text clipped - 9 lines] > keep you from creating and using base classes as long as they are not > declared as being abstract. But this means we can *only* use LINQ to Objects with your class, instead of with *anything implementing IEnumerable<T>*. To me, the latter is a big "plus" for LINQ.
> > If I seal a class, I don't want anybody to override its internal behaviour, > > and that is the only condition for sealing it. I would have no problem with [quoted text clipped - 3 lines] > Please refer to my other reply where I gave an example of how to keep > internal behaviour solid without sealing a class. Don't forget method *hiding* as well as overriding. If I were able to declare:
FooString x = new FooString(...);
then x.Equals may well have nothing to do with the normal string.Equals behaviour.
I'm very happy with string having been sealed. I just wish classes were sealed by default.
> > in the same way that I would have no problem with somebody > > writing a utility class that accepted my class as a parameter and performed > > work with it. In fact, I just described Extension methods right there --- > > syntactical sugar. > > Yep, syntactical sugar for having ignored OOA. My humble opinion still. I don't think you can really claim it's your "humble" opinion when you write things like:
"Extension Methods in .NET is a slap in the face of all serious software engineers."
That's not humble at all.
> > Perhaps so, but why is that such a problem? > > 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. When debugging, I don't normally say "I'll look at all the code in a certain class" - I say "I'll look at all the code in a particular flow of execution". That will *often* include code from multiple classes; this is no different.
> > 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. > > Helper classes are usually a good example for procedural code > disguised as OOD. Not in my view.
> I'd regard any such as bad. They don't help. I > can't discuss with you on your example without having seen your code. > But if you'd like to add a function to SqlConnection then why don't > you just create a derivate class then? Inheritance appears to be your answer to everything, despite its massive issues when introducing new behaviour.
For a start, you can't always decide which type you'll actually get. If you're using an API which returns SqlConnection, what are you going to do? You could write a wrapper class instead, I suppose - but that's a different answer and not significantly different to writing helper methods.
Inheritance is great for *specializing* behaviour, but not for writing behaviour which is valid for *all* instances of a particular class. Extension methods are great for the latter, and work with interfaces too.
> Or why are you using it so massively at all? It's a technical class > that should be hidden somewhere in a data access layer class > hierarchy. You make it sound as if the code in the DAL doesn't really exist. Sure, SqlConnection shouldn't be used outside the DAL - but within the DAL, it may be used fairly heavily.
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk
Axel Dahmen - 03 Apr 2008 09:09 GMT > For example, Marc > Gravell and I recently wrote a "push" version of LINQ by implementing > the same set of operators as extensions on a different interface. I've got to go to my job... Just a quick note on this: So you've actually *written* extensions yourself? So what's the advantage then? Where's the agnostic point? (This might be a stupid quick question. Just wanted to give it before I leave home..)
Regards, Axel
Jon Skeet [C# MVP] - 03 Apr 2008 09:32 GMT > > For example, Marc > > Gravell and I recently wrote a "push" version of LINQ by [quoted text clipped - 3 lines] > I've got to go to my job... Just a quick note on this: So you've > actually *written* extensions yourself? So what's the advantage then? Our LINQ operators work in a different way, which has advantages in a few situations, but make life more complicated in others.
> Where's the agnostic point? (This might be a stupid quick question. > Just wanted to give it before I leave home..) The "agnostic" side is that I can still use a C# query expression with my own LINQ implementation. C# doesn't care where the Select/Where/SelectMany etc methods come from.
See http://msmvps.com/blogs/jon.skeet/archive/2008/01/04/quot-push-quot- linq-revisited-next-attempt-at-an-explanation.aspx
for more on this.
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk
Alex Clark - 05 Apr 2008 00:36 GMT >> So you want a specialised inherited class for everything in the framework >> that implements IEnumerable? What happens when I create my own >> IEnumerable >> class and I want that to provide me with LINQ services, what do I do >> then?
>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.
>>Helper classes are usually a good example for procedural code disguised as >>OOD. I'd regard any such as bad. They don't help. I >>can't discuss with >>you on your example without having seen your code. But if you'd like to >>add a function to SqlConnection then >>why don't you just create a >>derivate class then? 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.
>>Or why are you using it so massively at all? It's a technical class that >>should be hidden somewhere in a data access layer class >>hierarchy. 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
Axel Dahmen - 08 Apr 2008 08:39 GMT > 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 [quoted text clipped - 5 lines] > 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 [quoted text clipped - 3 lines] > 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 [quoted text clipped - 6 lines] > 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 [quoted text clipped - 4 lines] > 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
Jon Skeet [C# MVP] - 30 Mar 2008 07:50 GMT > > You're welcome to your opinion, even if you cannot be bothered to express > > it in a polite, respectful way. Nevertheless, suffice to say your opinion [quoted text clipped - 6 lines] > keeping an objects methods within the object (a typical OOD pattern) > while at the same time accepting Extension Methods? Very, very simply:
1) Not all actions which logically act "on" an object need to change that object's state
2) Not all actions which are desirable in terms of appearing to act "on" an object can be anticipated by the class's original designer
3) Using inheritance to add these kinds of actions isn't always possible, and inheritance comes with many penalties in terms of design.
Traditionally, static methods have been the way of getting round this - I'm sure you've seen utility classes just full of methods to operate on streams, or strings etc. Extension methods just means that when you use the methods in those utility classes, they're available in a more transparent way.
Unless you're actually debugging into the method in question, you don't really need to know whether it was provided by the original class or as an extension method. When you need to know, it's easy to find out - when you *don't* need to know, the more natural syntax aid's readability.
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk
Axel Dahmen - 31 Mar 2008 07:06 GMT >> How can someone possibly argue about >> keeping an objects methods within the object (a typical OOD pattern) [quoted text clipped - 7 lines] > 2) Not all actions which are desirable in terms of appearing to act > "on" an object can be anticipated by the class's original designer You are right.
Regarding 1): That's common usage. But functions that mainly interact with some other object's properties should be move to the object (or a derivate). They can, of course, be implemented somewhere else, but this shouldn't be a common usage.
Regarding 2): In fact, they *can't*. That's what inheritance is made for.
> 3) Using inheritance to add these kinds of actions isn't always > possible, and inheritance comes with many penalties in terms of design. [quoted text clipped - 4 lines] > the methods in those utility classes, they're available in a more > transparent way. I fully agree with you. That's the purpose of Expansion Methods. Yet I didn't use any such utility classes ever (except for testing or when I'm in a hurry). Using these is a procedural way of thinking, but not OOD.
Well, OK, I see a point when programming in VB because this language has been procedural for a long time now. OOD is new there and probably not necessary. I must admit that I'm solely thinking of C# and the .NET framework in my argumentation.
> Unless you're actually debugging into the method in question, you don't > really need to know whether it was provided by the original class or as > an extension method. When you need to know, it's easy to find out - > when you *don't* need to know, the more natural syntax aid's > readability. It does, for sure. ...given that such static methods have been implemented in the first place. Which is what should be avoided (which is the more or less abstract topic of my thread).
Regards, Axel Dahmen
Jon Skeet [C# MVP] - 31 Mar 2008 09:04 GMT > >> How can someone possibly argue about > >> keeping an objects methods within the object (a typical OOD pattern) [quoted text clipped - 14 lines] > a derivate). They can, of course, be implemented somewhere else, but > this shouldn't be a common usage. Using inheritance unnecessarily to add functionality is:
a) impossible in many situations (e.g. when the class is sealed) b) undesirable in many other situations
Personally I prefer most classes to be sealed - there is a design cost to inheritance, which should not be overlooked. See
http://msmvps.com/jon.skeet/archive/2006/03/04/inheritancetax.aspx
> Regarding 2): In fact, they *can't*. That's what inheritance is made for. No - inheritance is made for *specializing* behaviour, not representing other behaviour which is still appropriate to *every* instance of the base type.
> > 3) Using inheritance to add these kinds of actions isn't always > > possible, and inheritance comes with many penalties in terms of design. [quoted text clipped - 6 lines] > > I fully agree with you. That's the purpose of Expansion Methods. Extension methods, not expansion methods.
> Yet I didn't use any such utility classes ever (except for testing or > when I'm in a hurry). Using these is a procedural way of thinking, > but not OOD. Two examples in my own experience:
1) String utility routines. We can't derive from string, nor could we force every instance of string returned by the library methods to be an instance of our own string type even if we could. Where, then, would you write utility methods for strings? Such methods are *very* common.
2) Stream routines, e.g. to read the whole of a stream into a byte array, or copy the contents of one stream to another. These are very commonly mis-implemented operations, so it's good to have them in one place. They can operate on *any* stream, so inheritance is inappropriate. Static method taking a stream is entirely consistent with this situation - and extension methods make them easier to use.
> Well, OK, I see a point when programming in VB because this language > has been procedural for a long time now. OOD is new there and [quoted text clipped - 10 lines] > implemented in the first place. Which is what should be avoided > (which is the more or less abstract topic of my thread). Okay, so really you want to virtually abolish static methods. Sorry, can't agree there. I rather like being able to use LINQ operations on *any* IEnumerable<T> rather than having to construct an instance of MyLinq<T> every time. It sounds like you want to force people to artificially create an instance of a type for *no reason* other than to avoid using static methods.
I don't think that's a pragmatic or sensible approach.
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk
Axel Dahmen - 03 Apr 2008 08:45 GMT > Using inheritance unnecessarily to add functionality is: > > a) impossible in many situations (e.g. when the class is sealed) > b) undesirable in many other situations You are right. I'd even go further: I'd say that doing *anything* unnecessarily is undesirable in many situations. ;)
> Personally I prefer most classes to be sealed - there is a design cost > to inheritance, which should not be overlooked. See > > http://msmvps.com/jon.skeet/archive/2006/03/04/inheritancetax.aspx I've read your interesting article. Please refer to one of my recent posts here from today regarding how to keep a design stable without sealing.
>> Regarding 2): In fact, they *can't*. That's what inheritance is made for. > > No - inheritance is made for *specializing* behaviour, not representing > other behaviour which is still appropriate to *every* instance of the > base type. Again I agree with you. Could you give a quick example of > representing other behaviour < that's appropriate for this discussion? I frankly can't see an issue here.
>> I fully agree with you. That's the purpose of Expansion Methods. > > Extension methods, not expansion methods. Yep, right. Got to hurry over the keys sometimes... Yet, where's the difference?
> Two examples in my own experience: > > 1) String utility routines. We can't derive from string, nor could we > force every instance of string returned by the library methods to be an > instance of our own string type even if we could. Where, then, would > you write utility methods for strings? Such methods are *very* common. Is this really common? I've never seen some kind of StringHelper class. Yet I've seen many member functions taking a string object as parameter without being string itself. Yet, all these functions didn't change a string's state. In fact they actually can't. But I know the StringBuilder class which is a perfect example of not using Extension Methods but a discrete class.
> 2) Stream routines, e.g. to read the whole of a stream into a byte > array, or copy the contents of one stream to another. These are very > commonly mis-implemented operations, so it's good to have them in one > place. They can operate on *any* stream, so inheritance is > inappropriate. Static method taking a stream is entirely consistent > with this situation - and extension methods make them easier to use. Again I'd like to see a short example of how Extension Methods would to a trick common OOA implementation grounds don't cover gracefully.
> Okay, so really you want to virtually abolish static methods. Sorry, > can't agree there. I rather like being able to use LINQ operations on [quoted text clipped - 4 lines] > > I don't think that's a pragmatic or sensible approach. OK, we have a disagreement here. But still you will see that debugging Extension Methods and maintaining applications using them will become a big hassle. *That's* in fact the reason for avoiding to use static methods.
Jon Skeet [C# MVP] - 03 Apr 2008 09:06 GMT > > Using inheritance unnecessarily to add functionality is: > > [quoted text clipped - 3 lines] > You are right. I'd even go further: I'd say that doing *anything* > unnecessarily is undesirable in many situations. ;) And yet you're happy to introduce inheritance all over the place unnecessarily, it seems, just to avoid static methods.
> > Personally I prefer most classes to be sealed - there is a design cost > > to inheritance, which should not be overlooked. See [quoted text clipped - 4 lines] > posts here from today regarding how to keep a design stable without > sealing. You haven't answered most of the problems of inheritance though, nor have you considered the possibilities of new methods which hide existing methods instead of overriding them.
I'm still happy with sealed classes, and wish it were the default in C#.
> >> Regarding 2): In fact, they *can't*. That's what inheritance is made for. > > [quoted text clipped - 5 lines] > representing other behaviour < that's appropriate for this > discussion? I frankly can't see an issue here. LINQ to Objects is the *obvious* example. The idea of filtering (Where) or projecting (Select) is valid for all IEnumerable<T>. Why should I restrict it to a particular derived class.
> >> I fully agree with you. That's the purpose of Expansion Methods. > > > > Extension methods, not expansion methods. > > Yep, right. Got to hurry over the keys sometimes... Yet, where's the > difference? One is a technically correct term, the other isn't.
> > Two examples in my own experience: > > [quoted text clipped - 9 lines] > know the StringBuilder class which is a perfect example of not using > Extension Methods but a discrete class. Pretty much every project I've worked on in .NET and Java has had things like this. StringBuilder is a class which works on a string repeatedly - I'm talking about methods like "escape with backslashes" or "encode HTML entities" etc.
> > 2) Stream routines, e.g. to read the whole of a stream into a byte > > array, or copy the contents of one stream to another. These are very [quoted text clipped - 5 lines] > Again I'd like to see a short example of how Extension Methods would > to a trick common OOA implementation grounds don't cover gracefully. With extension methods, I can use LINQ to Objects with any IEnumerable<T>. With your suggested "solution" I'd have to create a new instance of some derived class *every time I wanted to do anything*, completely unnecessarily.
> > Okay, so really you want to virtually abolish static methods. Sorry, > > can't agree there. I rather like being able to use LINQ operations on [quoted text clipped - 9 lines] > will become a big hassle. *That's* in fact the reason for avoiding to > use static methods. No, I don't see that at all - not when they're used judiciously. If they're used all the time, completely arbitrarily, they'll cause issues - but the same is true for anything (and particularly true for inheritance, by the way - the deeper the inheritance hierarchy, the harder debugging is IME).
 Signature Jon Skeet - <skeet@pobox.com> http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet World class .NET training in the UK: http://iterativetraining.co.uk
Alex Clark - 31 Mar 2008 20:41 GMT I fully agree with you. That's the purpose of Expansion Methods. Yet I didn't use any such utility classes ever (except for testing or when I'm in a hurry). Using these is a procedural way of thinking, but not OOD.
So you've honestly never used static methods for anything? No static class containing methods to handle, say, string-formatting specific to the data you're dealing with? I would like to know how you've avoided creating utility/helper classes & functions all these years, but I truly hope it's not just a case of "I put them all into a formatting class which I instantiate and call the methods of as needed"...
Well, OK, I see a point when programming in VB because this language has been procedural for a long time now. OOD is new there and probably not necessary. I must admit that I'm solely thinking of C# and the .NET framework in my argumentation.
I think this is indicative of you not understanding the framework. VB has existed for much, much longer than C# and had the beginnings of OOD as of version 4 (mid 90s?) when MS first introduced classes into the language. When .NET was released, C# and VB.NET were released at the same time. Both support an identical set of OOD tools. VB.NET is no more or less procedural than C#, it's just a different syntax of what is essentially the same language under the hood. OOD is no newer in VB.NET than it is in C#, and arguably it's existed in VB for longer due to VB's age.
In fact, .NET was in Beta back in 2000, so I wouldn't class 8yrs of OOD in either language as being particularly *new*, unless you're only just starting to use the framework yourself?
...given that such static methods have been implemented in the first place. Which is what should be avoided (which is the more or less abstract topic of my thread).
Which causes me to raise my earlier question once again: have you honestly gone through life as an OOD programmer and avoided static methods as though they carry some form of disease? When there is a need for utility and helper functions, how have you implemented these?
Regards, Alex
Axel Dahmen - 03 Apr 2008 08:56 GMT > So you've honestly never used static methods for anything? No static class > containing methods to handle, say, string-formatting specific to the data > you're dealing with? I would like to know how you've avoided creating > utility/helper classes & functions all these years, but I truly hope it's > not just a case of "I put them all into a formatting class which I > instantiate and call the methods of as needed"... 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.
> I think this is indicative of you not understanding the framework. VB has > existed for much, much longer than C# and had the beginnings of OOD as of > version 4 (mid 90s?) when MS first introduced classes into the language. 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.
> When .NET was released, C# and VB.NET were released at the same time. Both > support an identical set of OOD tools. VB.NET is no more or less procedural > than C#, it's just a different syntax of what is essentially the same > language under the hood. OOD is no newer in VB.NET than it is in C#, and > arguably it's existed in VB for longer due to VB's age. Hey hey... Did you read *anything* in my previous post that said "VB.NET"?? I just wrote that I don't know VB.NET as I didn't use it yet. Of course it has the same CLR C# and J# and any other .NET language has. Yet it has its own extensions left. Just refer to the logical operators. I just don't know them all. That's what I said. Nothing more. Nothing less.
Regards, Axel
Alex Clark - 04 Apr 2008 23:52 GMT >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
|
|