Jeff,
If you’re looking to beef up your library, I just releases the first version of the .NET Extension Library: http://www.codeplex.com/nxl/.
It largely consists of pretty run of the mill stuff, but the focus going forward will be to add classes and interfaces beyond extension methods that form the basis of a good framework (such as an abstraction to logging so you don’t have log4net code spread out everywhere).
The first such enhancement is already there, in the form of an ICache interface which abstracts away an improved caching API (so it’s easier to test). Here’s my favorite sample code from it:
User user = CacheFactory.GetInstance.Fetch
(
user.{0}.Sub(userId),
() = _dataStore.GetUser(userId),
3.DaysFromNow()
);
The 2nd parameter is the callback to invoke if the value wasn’t in the cache - saving you from having to write repetitive code.
Yes monkeypatching is bad… but at least C# doesn’t let you do it.
I think the point is always overlaboured about not reinventing the wheel. Yes its a waste of time, but those great programmers who wrote the first code were probably nothing special either… just as prone to making mistakes and doing things badly. Further they probably comprimised to find a best fit function to as many scenarios as possible.
Monkeypatching is bad, but reinventing the wheel is not necessarily that bad.
Yes… I have made my own programming languages in my spare time. I do love reinventing the wheel… but on the other hand at least I used flex, bison and loads of the stdlib functions to do so… at least after the first time.
Still… why even bother with monkeypatching. Derive a new class or something… then at least if you reinvent a wheel or two, your buggy code is not likely to break other things left, right and centre.
Anders Heljberg is a respected language designer? WTF? He implemented Pascal, then Java, then Microsoft-Java (aka C#). When did he become a language designer in the same league as Wirth, Stroustrup, Codd, etc?
I wonder what’s next? Duck typing probably - after all, no-one wants to write code that has to be designed in the new world of ‘its so easy’ .NET, not when they can just hack it about until it (fingers crossed) works like they want. I just pity the poor engineers who have to perform maintenance on all this code.
@AndyB:Anders Heljberg is a respected language designer? WTF? He implemented Pascal, then Java, then Microsoft-Java (aka C#). When did he become a language designer in the same league as Wirth, Stroustrup, Codd, etc?
Because God knows that AndyB is in a position to comment on the quality and the difficulty of writing 3 of the most well-known and used languages in the world.
And it’s Heljsberg, not Heljberg.
I find it deliciously ironic that in the horrible language you refer to, you wouldn’t experience this problem at all. It implements substr() just as syd suggests.
Don’t be scared of a language’s features. Learn how to use them.
A week ago a friend of mine related to me that a TCL primitive opened a program to a DOS attack. His answer was to rewrite the primitive in a manner immune to this. At the time he was in a reflective mood, and he did not call it monkey patching.
He also made a comment regarding teaching people, I could teach you TCL in five minutes. It would take you years to master it.
I’ve come to the conclusion that the best programmers are not the smartest ones. The ‘mediocre’ ones stick to regular practices and don’t adopt new features all the time for the hell of it. Their code is more consistent, better written/commented. The smart-arse mavericks always seem to want to prove themselves in their code by unneccesarily using techniques that they don’t fully understand themselves and don’t appreciate the full ramifications. Then they think that documentation is not for them and two years down the line, it’s their shite that someone else has to figure out.
There’s a reason some of the most deeply respected computer scientists in the world end up as language designers, and there is ALSO a reason why PHP is more popular, and has much more useful code, than Scheme.
The design goals of those scientists are strangely set apart from the design goals of programmers.
Anyway, those examples sound downright tame next to Forth, where you could change 0 to mean something else (for example). And, yet, Forth programmers learned to deal with it.
It’s a matter, curiously enough, of tradition. Of learning what works and what doesn’t, and passing that unconscious knowledge to your fellow programmers. We are seeing a spurt of innovation which will bring evolution to these languages, and like any evolution, some results are evolutionary dead ends.
While your heart is in the right place, what you’ve done feels unnatural in C#. Keep going, but try to preserve and augment the C# coding culture rather than change the way C# reads.
Sub: Confusing. Perhaps you could rename Sub() to AsFormat() or FormatFor() because it then reads ‘treat this string as a format string’ (except only will format 1 value). C# dev’s already grok string.Format(), so there’s no point introducing new terminology, especially when it’s overloading the same concept (conceptually). When you wrote Sub I thought SubString, not substitute (pesky Spartan programming techniques). Unless you’ve copied all of the overrides as well, you really need to have IFormatProvider overloads as well, and you’ve just made it a lot harder for code introspection tools like FXCop or even resharper.
DaysFromNow: There’s already a really good string format for TimeSpan’s, it’s of the form [ws][-]{ d | [d.]hh:mm[:ss[.ff]] }[ws] and in a library you’d need to provide heaps of overloads.
Considering cacheing should ALWAYS be configurable, you could then load the value from the (dreaded) Xml config.
TimeSpan expirationWindow = TimeSpan.Parse(ConfigurationManager.AppSettings[UserCacheExpirationWindow]);
In practice I’d never write 3.DaysFromNow() or int counter; counter.DaysFromNow(); Use extensions as if you were adding a method to the class itself. Plug (perceived) holes in the shipped framework and make the syntax easier to read, not just different. DateTimeExtension.DaysFromNow(3) is a lot easier to understand in my opinion, but then is that easier than DateTime.Now.AddDays(3)? Not really.
another example of the kind of code I see all the time:
DateTime startOfMonth = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 0, 0, 0);
versus
DateTime start = DateTime.Now.BeginningOfMonth(); // – this is the extension method
An example that comes to mind is a JSON implementation I’ve seen in javascript that modifies the prototypes of all the built in types, breaking anything and everything and that uses a for(… in …) loop and much more.
Could you use a color other than red to highlight the differences? It’s very, very hard for us red-green colorblind folks to pick up red text mixed in with black text.
@Daniel Cormier on July 14, 2008 09:05 AM
Could you use a color other than red to highlight the differences? It’s very, very hard for us red-green colorblind folks to pick up red text mixed in with black text.
Unfortunately, to people who are not color-blind, highlighting in red comes naturally. Red is an extremely vibrant color and contrasts well with both black and white - more so than any other color.
Which color do you think he should have used? Or maybe instead of changing the color, he should have just made the highlighted text bold as well?
If you love strings (okay… some strings are kind of sexy, but thats a completly other topic) why do you use them in a safe manner?
Don’t do s.Length == 0 use String.IsNullOrEmpty(s) instead and put a little bit more safety in your code. And use curly brackets { } with if … then … else. And please. If functions return something follow the microsoft standard and only use one return per function. It’s looking a bit longer but…
public static string Left(string s, int len)
{
string returnValue = ;
if (len != 0 !String.IsNullOrEmpty(s))
{
if (s.Length = len)
{
returnValue = s;
}
else
{
returnValue = s.Substring(0, len);
}
}
@ James:
Prototype plays very nice with any other framework and has for some time. I’ve used it with YUI and jQuery. Several years ago (v. 1.4, I think) Prototype added some methods to Object.prototype at which point users rebelled and the author, Sam Stephenson, rightly removed it.
First off, the mere fact that the author of Prototype.js thought it would be a good idea to modify the base object prototype is a pretty clear indication of problems at the core.
The use (and overloading of) the $() function also indicates problems, given that the $() function has a specified use, according the the ECMA specification.
I have to say that Prototype.js is a perfect example of monkeypatching.
Generally, it terrifies me. You can do that kind of thing in ActionScript/javascript, and I see it as potential security hole. If any random person can come by and redifine one of your private methods to do something different, then nothing is safe (though hopefully browsers will prevent things like that through XSS prevention).
However, it is also the only reason our product works. We depend on auto-generated SWF files built by a 3rd party tool, and the generated files are incredibly buggy. Monkeypatching allows me to fix the bugs at runtime by redefining the methods that don’t work properly (and also allow me to fix a couple bugs in the built-in Flash UI components too).