Extension Methods - Satan's favourite construct (controversial to nerds)
-
Sometimes I yearn for a return to .NET 2.0. The C# that came with it was a great language and now that generics were included it was essentially complete in my mind. Since then, they've been adding all sorts of dubious things to the language LINQ being the most notable but now we also have the async/await business which really is anything but the simple solution to asynchronous programming they tell us it is. Extensions methods, everyone's favourite encapsulation anti-pattern debuted with LINQ in order to make it work and some people (me) viewed them with suspicious eyes at the time but didn't really know how bad things could get. Having recently worked on a system where they have been abused to the fullest I can tell you. You start off with pretty hollow objects with very little in the way of methods, just enough to get at the data. Then, you put all your logic in extension methods, preferably in different assemblies. A sort of warped onion architecture. Now, any normal developer who goes looking for a type's methods won't find them in the type or even that assembly. A missing reference will make them disappear completely. Also, with careful planning, you can make it exceedingly hard to move that logic back where it belongs because doing so will cause all kinds of circular dependency issues. Immutable code! Shocking stuff, but if you really hate the world, don't forget the Action<> and Func<> delegates. These are useful because you can avoid passing meaningful data to methods. Instead just pass delegates everywhere (a functional programming approach I'm told). This makes it practically impossible for anyone to work out the execution flow by examining the code. Combine the two and you have one thoroughly malevolent system. People bang on about patterns all the time in software development, but if you ask me (I'm aware you didn't) the way to build a good system is to always, always, always keep everything as simple as you can make it.
Regards, Rob Philpott.
Couldn't agree more although I don't have anything against LINQ or extension methods I use them sparingly, preferring the simple, easy to understand by someone else in 18 months time approach.
"If you think it's expensive to hire a professional to do the job, wait until you hire an amateur." Red Adair. nils illegitimus carborundum me, me, me
-
Rob Philpott wrote:
otherwise it's a dangerous thing. In the wrong hands.
You could do dangerous things, even back in 2.0. Ultimately, any tool in the hands of a tool can be misused and abused.
I was brought up to respect my elders. I don't respect many people nowadays.
CodeStash - Online Snippet Management | My blog | MoXAML PowerToys | Mole 2010 - debugging made easierPete O'Hanlon wrote:
Ultimately, any tool in the hands of a tool can be misused and abused.
I think that may imply the following corollary: "any tool that hands a tool to a tool, without knowing the tool receiving the tool knows how to properly use it, is, potentially, abusing, and misusing, themselves, and two other tools." yours, Bill
“Be patient toward all that is unsolved in your heart, and try to love the questions themselves, like locked rooms, and like books that are now written in a very foreign tongue. Do not now seek the answers, which cannot be given you because you would not be able to live them. And the point is, to live everything. Live the questions now. Perhaps you will then gradually, without noticing it, live along some distant day into the answer.”
Rainer Maria Rilke
-
True, but that static helper would be in a different class and it would be clear to the reader what was going on. Extension methods exist in one type but masquerade as belonging to another, and break encapsulation because their logic is defined outside of the affected type.
Regards, Rob Philpott.
Rob Philpott wrote:
break encapsulation
Not any more than a helper method on a helper class does. But, in general, I agree that overuse and misuse of extension methods should be avoided.
If your actions inspire others to dream more, learn more, do more and become more, you are a leader.-John Q. Adams
You must accept one of two basic premises: Either we are alone in the universe, or we are not alone in the universe. And either way, the implications are staggering.-Wernher von Braun
Only two things are infinite, the universe and human stupidity, and I'm not sure about the former.-Albert Einstein -
But what about CollectionUtils.ForEach(collection, item => { ... })? It's the hiding of the actual location of the code that really gets me about extension methods, and it doesn't gain enough over that snippet to be worth the opacity, imo.
BobJanova wrote:
CollectionUtils.ForEach(collection, item => { ... })
That would not work with the extension that I used as the example.
BobJanova wrote:
It's the hiding of the actual location of the code that really gets me about extension methods
I would agree because I have no idea what you are doing with the collection you are passing in. You should not be using an extension here as it is not intuitive.
BobJanova wrote:
and it doesn't gain enough over that snippet to be worth the opacity
Extensions should not be opaque, but actually clearly state what it is doing. That is my point. If this is not the case then you are doing it wrong.
Computers have been intelligent for a long time now. It just so happens that the program writers are about as effective as a room full of monkeys trying to crank out a copy of Hamlet.
-
Sometimes I yearn for a return to .NET 2.0. The C# that came with it was a great language and now that generics were included it was essentially complete in my mind. Since then, they've been adding all sorts of dubious things to the language LINQ being the most notable but now we also have the async/await business which really is anything but the simple solution to asynchronous programming they tell us it is. Extensions methods, everyone's favourite encapsulation anti-pattern debuted with LINQ in order to make it work and some people (me) viewed them with suspicious eyes at the time but didn't really know how bad things could get. Having recently worked on a system where they have been abused to the fullest I can tell you. You start off with pretty hollow objects with very little in the way of methods, just enough to get at the data. Then, you put all your logic in extension methods, preferably in different assemblies. A sort of warped onion architecture. Now, any normal developer who goes looking for a type's methods won't find them in the type or even that assembly. A missing reference will make them disappear completely. Also, with careful planning, you can make it exceedingly hard to move that logic back where it belongs because doing so will cause all kinds of circular dependency issues. Immutable code! Shocking stuff, but if you really hate the world, don't forget the Action<> and Func<> delegates. These are useful because you can avoid passing meaningful data to methods. Instead just pass delegates everywhere (a functional programming approach I'm told). This makes it practically impossible for anyone to work out the execution flow by examining the code. Combine the two and you have one thoroughly malevolent system. People bang on about patterns all the time in software development, but if you ask me (I'm aware you didn't) the way to build a good system is to always, always, always keep everything as simple as you can make it.
Regards, Rob Philpott.
Rob Philpott wrote:
Then, you put all your logic in extension method
Kids always abuse their toys.
Rob Philpott wrote:
These are useful because you can avoid passing meaningful data to methods. Instead just pass delegates everywhere (a functional programming approach I'm told).
Kids get easily bored - so they play with a lot of toys.
Rob Philpott wrote:
the way to build a good system is to always, always, always keep everything as simple as you can make it.
Yes but kids never worry about where the money comes from to buy the toys nor who cleans up the mess after they are put to bed (screaming and crying of course.)
-
Rob Philpott wrote:
A sort of warped onion architecture. Now, any normal developer who goes looking for a type's methods won't find them in the type or even that assembly.
Hmmm... I'll just say, it seems you are doing it wrong then. I use extension methods, but only to the point where it is obvious and could easily be added by re-inventing the wheel right then and there on the spot. For example, I often use
IEnumerable<T>
but prefer many of the Extensions offered by LINQ when using IList. Not too difficult to make myself.public static void ForEach<T>(this IEnumerable<T> collection, Action<T> action)
{
foreach (var item in collection)
{
action(item);
}
}I package it up and call it a done deal and use it. Now if a developer can not figure out what
SomeRandomCollection.ForEach(item => {//Do stuff});
means then I do not want them working in my code base anyways. Granted extensions can and will be abused. But that is true of any feature.Computers have been intelligent for a long time now. It just so happens that the program writers are about as effective as a room full of monkeys trying to crank out a copy of Hamlet.
Collin Jasnoch wrote:
Now if a developer can not figure out what ... means then I do not want them working in my code base anyways.
Myself if I suspect that the average developer is not going to be able to figure out my code, with their average skills, then I haven't done my job correctly.
-
Rob Philpott wrote:
I see no benefit in the piece of code you show above.
It may just be my opinion but I find this
collection.ForEach(item =>
{
//DoStuff
});more readable than
foreach(var item in collection)
{
//DoStuff
}or
foreach(SomeDependentObject item in collection)
{
//DoStuff
}or
for(int i = 0; i < collection.Count(); i++)
{
//DoStuff
}and so on and so forth. It seems more natural when I am coding. I am given the context (the collection) and then I run some action on it for each item.
Rob Philpott wrote:
What happens if an exception is thrown during iteration?
Well then an exception happens as it would with any of the iteration styles above.
Rob Philpott wrote:
You can't tell - depends on what the extension method does.
This is my point. If your extension is complicated and verbose you are doing it wrong. It should be simple and highly intuitive of what it is doing and any exceptions that are being passed in to the extension should not be captured by the extension but show up where the exception actually occurred. This is the nature of
static
class and has nothing to do with extensions other than that is how you implement extensions.Computers have been intelligent for a long time now. It just so happens that the program writers are about as effective as a room full of monkeys trying to crank out a copy of Hamlet.
Collin Jasnoch wrote:
It seems more natural when I am coding
Which is certainly reasonable as long as there is some guarantee that you are the sole person that will ever work on the code that you write. Most people don't have that luxury because they might like to move on to another job, or retire or even die and not have the business application cease to exist then. So writing code which many people find to be flat out obvious has a better chance of succeeding in such a situation.
-
>>What happens if an exception is thrown during iteration? You can't tell - depends on what the extension method does. Oh please. You can't see that when calling "normal" methods either. So you just put everything in one big god-method so you can see everything directly? You have the same intellisense, the same goto-definition etc on extension methods as on any other method. Abusing extension methods on System.Object etc is bad, but I fail to see how they are bad when used as intended. I've seen developers abuse other features like inheritance etc: public class Order : Address making order inherit address just because orders have a shipping address etc. Bad coders write bad code..
Roger Alsing wrote:
Bad coders write bad code..
So presumably you are claiming that your usage is correct and understandable. And it is only others that have problems? And perhaps only those that are less intelligent than you would have any trouble understanding it? What classes have you taken to issue that your usage is correct? What standards do you use to insure that your usage is something that most average developers would have or should have learned?
-
I am completely opposed to the AS operator. It causes more problems than it is worth. You talk about sloppy programming with extension methods, ugh, AS is worse. In fact, the AS keyword brought down an entire production system. (combined with a lazy programmer) The short story is that instead of relying on strong typing from the DB the developer used AS and converted the type to the expected type. Some DBA decided to change a database type without telling any one and a few weeks later another subsystem broke because of invalid data. Had the type been formally cast this error would have been caught immediately. I am of the camp that strong typing is important. Using conversion ... everywhere as AS encourages, only serves to disassociate developers from types (ok, this includes var) and types and the knowledge thereof is a fundamental underpinning of a stable, large system.
Need custom software developed? I do custom programming based primarily on MS tools with an emphasis on C# development and consulting. "And they, since they Were not the one dead, turned to their affairs" -- Robert Frost "All users always want Excel" --Ennis Lynch
-
Not really! They are extremely useful for interfaces especially and in those cases where the code is not really in your hand.
Rob Philpott wrote:
the way to build a good system is to always, always, always keep everything as simple as you can make it.
And extension methods can be used as a way to keep the code simple and non-repetitive. In fact you nailed it well. Keep the end code simple - minimize complexities and I do not see extension methods being a hurdle rather it can be a tool to do so.
Rama Krishna Vavilala wrote:
They are extremely useful for interfaces especially and in those cases where the code is not really in your hand.
Which suggests many problems such as a broken architecture, design or a misuse/misunderstanding of the architecture/design.
Rama Krishna Vavilala wrote:
and non-repetitive.
Rather certain there are other ways to achieve that.
-
It's just code. Deal with it.
If your actions inspire others to dream more, learn more, do more and become more, you are a leader.-John Q. Adams
You must accept one of two basic premises: Either we are alone in the universe, or we are not alone in the universe. And either way, the implications are staggering.-Wernher von Braun
Only two things are infinite, the universe and human stupidity, and I'm not sure about the former.-Albert Einsteinahmed zahmed wrote:
It's just code. Deal with it.
As a professional developer I don't just deal with code though. It is my responsibility to insure that, to the best of my ability, I deliver something that provides the best value to the business. I don't care if the next three developers think my code is boring. I would however have a problem if the next three developers were afraid to touch my code because the complexity was so high that they couldn't figure out.
-
You are touching on a very sore point for me; all these features encourage increasingly bad design. The saying goes "if all you have is a hammer, everything is a nail." Likewise, if what you have is "advanced" .NET 4.x, everything must use the same. Solutions which should be brain dead simple take on a monstrous complexity, especially with the developer who wants everything LINQ"ified". It seems to me that the zeal of getting things done rapidly, including various management methodologies, have trumped long term development and maintenance. My hypothesis is that the latter requires thinking, planning and patience. It more than pays off in the end, but that's not good enough to far too many developers and managers, far too many of them aren't smart enough to do it right anyway. It's simply easier to churn out code that kind of works for now and then quickly move on to another project or company, leaving the train wreck that's going to happen to someone else.
Joe Woodbury wrote:
You are touching on a very sore point for me; all these features encourage increasingly bad design.
Only to a limited extent. There are extreme cases but most development with 'clever' code has a smaller scope than would be normally covered by a real design. Of course since there is seldom anything even close to a real design - that is the real problem.
Joe Woodbury wrote:
It's simply easier to churn out code that kind of works for now and then quickly move on to another project
One must be agile like that.
-
Rob Philpott wrote:
otherwise it's a dangerous thing. In the wrong hands.
You could do dangerous things, even back in 2.0. Ultimately, any tool in the hands of a tool can be misused and abused.
I was brought up to respect my elders. I don't respect many people nowadays.
CodeStash - Online Snippet Management | My blog | MoXAML PowerToys | Mole 2010 - debugging made easierPete O'Hanlon wrote:
Ultimately, any tool in the hands of a tool can be misused and abused.
Which doesn't prove the converse. Just because someone does in fact use it 'correctly' doesn't mean that it in not in fact more complex than needed for the current business goals. And I suspect there are very few cases where it is required. And yet users will rationalize that their usage is justified.
-
Pete O'Hanlon wrote:
Ultimately, any tool in the hands of a tool can be misused and abused.
Which doesn't prove the converse. Just because someone does in fact use it 'correctly' doesn't mean that it in not in fact more complex than needed for the current business goals. And I suspect there are very few cases where it is required. And yet users will rationalize that their usage is justified.
jschell wrote:
Which doesn't prove the converse. Just because someone does in fact use it 'correctly' doesn't mean that it in not in fact more complex than needed for the current business goals.
Indeed not, nor did I claim otherwise. However, the Spidey maxim still holds true here "with great power comes great responsibility". I did have one really handy extension method in .NET 3.5, but .NET 4 provided me with the equivalent that helped me remove it. I had a string extension that checked for whitespace as well to check whether or not the string was empty. I also have a couple of WPF specific ones, but that's all I've ever really needed in my own code.
I was brought up to respect my elders. I don't respect many people nowadays.
CodeStash - Online Snippet Management | My blog | MoXAML PowerToys | Mole 2010 - debugging made easier -
ahmed zahmed wrote:
It's just code. Deal with it.
As a professional developer I don't just deal with code though. It is my responsibility to insure that, to the best of my ability, I deliver something that provides the best value to the business. I don't care if the next three developers think my code is boring. I would however have a problem if the next three developers were afraid to touch my code because the complexity was so high that they couldn't figure out.
Good points, all. Judicious use of tools is always appropriate though.
If your actions inspire others to dream more, learn more, do more and become more, you are a leader.-John Q. Adams
You must accept one of two basic premises: Either we are alone in the universe, or we are not alone in the universe. And either way, the implications are staggering.-Wernher von Braun
Only two things are infinite, the universe and human stupidity, and I'm not sure about the former.-Albert Einstein -
jschell wrote:
Which doesn't prove the converse. Just because someone does in fact use it 'correctly' doesn't mean that it in not in fact more complex than needed for the current business goals.
Indeed not, nor did I claim otherwise. However, the Spidey maxim still holds true here "with great power comes great responsibility". I did have one really handy extension method in .NET 3.5, but .NET 4 provided me with the equivalent that helped me remove it. I had a string extension that checked for whitespace as well to check whether or not the string was empty. I also have a couple of WPF specific ones, but that's all I've ever really needed in my own code.
I was brought up to respect my elders. I don't respect many people nowadays.
CodeStash - Online Snippet Management | My blog | MoXAML PowerToys | Mole 2010 - debugging made easierThat's where I add most of my (few) extensions: pre-existing sealed classes or interfaces.
If your actions inspire others to dream more, learn more, do more and become more, you are a leader.-John Q. Adams
You must accept one of two basic premises: Either we are alone in the universe, or we are not alone in the universe. And either way, the implications are staggering.-Wernher von Braun
Only two things are infinite, the universe and human stupidity, and I'm not sure about the former.-Albert Einstein -
Joe Woodbury wrote:
You are touching on a very sore point for me; all these features encourage increasingly bad design.
Only to a limited extent. There are extreme cases but most development with 'clever' code has a smaller scope than would be normally covered by a real design. Of course since there is seldom anything even close to a real design - that is the real problem.
Joe Woodbury wrote:
It's simply easier to churn out code that kind of works for now and then quickly move on to another project
One must be agile like that.
jschell wrote:
Only to a limited extent.
I believe it is to a great, if not massive, extent. I have observed over the years that complex software tools and languages tend to result in increased complexity in all parts of a solution. I believe that the developers and architects "see" the solution through the lens of what surrounds it. In many cases it's as though they become blind to simplicity. Very trivial examples are the countless times I've seen vector used when a simple array would suffice. A less trivial example are designs involving a complex class hierarchy with extensive collections and multiple threads when a simple class, some global objects and one or two threads would be sufficient. (Another example is an architecture I dealt with which used WCF while plain sockets would have resulted in smaller, simpler and faster code which would have been much easier to maintain. It wouldn't have taken much longer to write and would have avoided a continual source of problems which easily added hundreds of hours of time to the full development process.)
jschell wrote:
Of course since there is seldom anything even close to a real design - that is the real problem.
True.
-
Roger Alsing wrote:
Bad coders write bad code..
So presumably you are claiming that your usage is correct and understandable. And it is only others that have problems? And perhaps only those that are less intelligent than you would have any trouble understanding it? What classes have you taken to issue that your usage is correct? What standards do you use to insure that your usage is something that most average developers would have or should have learned?
I'm in danger of getting a man crush on you. I'm having a similar issue with a guy at work, who is exceedingly clever, and has written all sorts of clever extension methods, and other goodies, without documentation or comment - so in order to program successfully on the system his solution is to ask him how to do it! your responses here may well be used against him :)
MVVM# - See how I did MVVM my way ___________________________________________ Man, you're a god. - walterhevedeich 26/05/2011 .\\axxx (That's an 'M')
-
ahmed zahmed wrote:
It's just code. Deal with it.
As a professional developer I don't just deal with code though. It is my responsibility to insure that, to the best of my ability, I deliver something that provides the best value to the business. I don't care if the next three developers think my code is boring. I would however have a problem if the next three developers were afraid to touch my code because the complexity was so high that they couldn't figure out.
It's gone beyond a crush, now I want your children.
MVVM# - See how I did MVVM my way ___________________________________________ Man, you're a god. - walterhevedeich 26/05/2011 .\\axxx (That's an 'M')
-
Sometimes I yearn for a return to .NET 2.0. The C# that came with it was a great language and now that generics were included it was essentially complete in my mind. Since then, they've been adding all sorts of dubious things to the language LINQ being the most notable but now we also have the async/await business which really is anything but the simple solution to asynchronous programming they tell us it is. Extensions methods, everyone's favourite encapsulation anti-pattern debuted with LINQ in order to make it work and some people (me) viewed them with suspicious eyes at the time but didn't really know how bad things could get. Having recently worked on a system where they have been abused to the fullest I can tell you. You start off with pretty hollow objects with very little in the way of methods, just enough to get at the data. Then, you put all your logic in extension methods, preferably in different assemblies. A sort of warped onion architecture. Now, any normal developer who goes looking for a type's methods won't find them in the type or even that assembly. A missing reference will make them disappear completely. Also, with careful planning, you can make it exceedingly hard to move that logic back where it belongs because doing so will cause all kinds of circular dependency issues. Immutable code! Shocking stuff, but if you really hate the world, don't forget the Action<> and Func<> delegates. These are useful because you can avoid passing meaningful data to methods. Instead just pass delegates everywhere (a functional programming approach I'm told). This makes it practically impossible for anyone to work out the execution flow by examining the code. Combine the two and you have one thoroughly malevolent system. People bang on about patterns all the time in software development, but if you ask me (I'm aware you didn't) the way to build a good system is to always, always, always keep everything as simple as you can make it.
Regards, Rob Philpott.
That's just a load of ... LINQ makes working with collections so much easier. I can simply order any collection, or combine lists, get unique values from a list that contains double values etc. etc. Imagine that each collection I made would have to implement its own sorting functionality... I could make a static sort method, but that is actually what LINQ is too, with the difference that you can use them as instance methods (but don't have to). Furthermore when using LINQ to SQL or LINQ to Entities you get a bonus of moving your queries from in-code strings to strong typed and easy to read LINQ queries. How is that any worse than using SP's in your database (which to me are king of like black boxes since they're out of your code) and/or strings in code? The Func<> and Action<> delegates prevent me from having all kinds of 1-line methods in my class that clutter up code. Functional programming has lots of good stuff, but works very different than OOP. Having some of it integrated in an OOP language is not bad per se, but it seems you're not very open to change. I read your profile and only 10 years ago you thought nothing could beat C++, now you think nothing can beat .NET 2.0. I'm not saying .NET 4.x doesn't have its flaws, but it has everything .NET 2.0 has and more. Wether you use it is up to you, but it's there for a reason: to solve all kinds of problems and issues (and does so when used right). Maybe in a couple of years you'll think that nothing can beat .NET 4.0... Or maybe you'll be doing F# by then and nothing will beat that... I got some bad news for you, but I think the problem here... is you.
It's an OO world.
public class Naerling : Lazy<Person>{
public void DoWork(){ throw new NotImplementedException(); }
}