Why Making C# Look Like Ruby is NOT “the Tits”

by bob on May 24, 2007

There is much buzz about Ruby these days, and apparently Ruby Envy is developing amongst some users of static languages. A case in point: Scott Hanselman recently published an article on his blog entitled “Programmer Intent (or What You’re Not Getting About Ruby And Why It’s The Tits)“. The basic premise is that Ruby is a more naturally expressive syntax, and he gave the following contrived example:

Java:

new Date(new Date().getTime() - 20 * 60 * 1000)

Ruby:

20.minutes.ago

Not to be outdone, Phil Haack pointed out that C# 3.0 would soon save the day for C# developers with Ruby envy by providing extension methods. He then tossed together a proof of concept showing that you could use extension methods to cruft this Ruby-like syntax:

20.Minutes().Ago();

And, with a probable future implementation of extension properties, you could probably even get rid of the parentheses. Woo hoo! Next thing you know they’ll add extension line endings and you can redefine the semicolon away, too!

I like C# extension methods, but I also have to wonder if they don’t carry within them the seeds of destruction.

Do you really want to walk into a new project someday and be confronted with some alien syntax that reflects the tastes of some slightly twisted dweeb who hasn’t been around for two years, and left no documentation? The talent to write solid application software does not necessarily make you a competent language architect.

Didn’t we used to make fun of C and C++ developer’s abuse of macros for this very reason? Don’t we already have 8,452 possible APIs we could call, including at least 2,467 horribly misbegotten ones? How far do we want to push this?

This kind of ability to redefine the language is giving people a license to shoot themselves in the foot, and possibly blow their whole leg off at the knee, and yours along with it. We should not use these kinds of techniques to shape-shift C# into something it’s not. The whole reasons for ECMA standards and the like is so that we can have some confidence that all implementations of the language are going to describe the same grammar and work in the same fashion.

Look, there is nothing magic about Ruby syntax. It’s just as unnatural as any other syntax. If it were “natural” it would be indistinguishable from plain English (or French or whatever) and we developers would be out of a job. But for certain tasks, and for certain people, Ruby syntax is less unnatural, and so Ruby can and arguably should be used in those contexts.

Let C# be used where it is appropriate, too. And enjoy those extension methods, but don’t try to re-invent C# with them.

{ 4 comments… read them below or add one }

Scott Hanselman May 24, 2007 at 10:25 pm

Interesting points! I agree that making C# “look like Ruby” is silly, unless the C# community decides that it’s a good idea. We haven’t agreed on an “aesthetic” like the Rails folks have, we pretty much follow Ander’s lead.

Aaron Davis May 25, 2007 at 5:53 am

I see your point, in that there is no reason to force ruby syntax on C#. However, I don’t think the example given has anything to do with syntax. Expressiveness comes from what you can do, not from the syntax. Syntax can only have the effect of making it easier to do something. The example given was already possible in C#; just not for built-ins. It has nothing to do with syntax. Extensions methods are really about mixins.

If you think about it, things like DateTime.Now (and properties in general) are no less “magical” than 20.Minutes.Ago, and I doubt you would be complaining if that particular construct where baked into C#.

I also find the force of your argument a bit disturbing, largely because I have to work with people who seem to think like this, only with a much fiercer intensity than you express. I was told early on here that I shouldn’t use the ternary operator, because perhaps not everyone was familiar with it. That is a dangerous attitude, and ensures that the quality of code remains low. Look, new APIs are being developed all the time. You have mentioned (I think) using DotNetNuke. That has an API to learn. I fail to see how something like the above example is any different.

I think that being allowed to extend the language to make code more clear is a good thing, and I don’t see how something like extension methods is really fundamentally different than being able to define your own class. Sure, you can “shoot yourself in the foot,” (I never really understood that term applied to programming) insofar as it was already possible. All that means is that you need to learn how to use the language, and any features it comes with, and document the hell out of your APIs — but then, you should have been doing that anyway.

Bob responds: Some features are easily mis-used, and deserve stronger cautions against their mis-use. Like you, I agree that we shouldn’t avoid using advanced or seldom-used features where appropriate, just because others might not be familiar with it. There’s these things called help files and intellisense and Google, so that’s really no excuse so long as we aren’t just showing off and introducing needlessly complex, obtuse or undocumented solutions.

But when we blur the apparent line between userland code and CLR features, we have to be careful. Yes, with extensions we’re technically not reinventing the language, any more than (and maybe less than) C++ macros create new grammars. We may introduce new but community-accepted conventions that are useful, but we may also barnacle code with ill-advised ornamentation as well. I simply don’t want to depart so much from common broadly accepted usage and convention that I have to scale a wall for every code base I lay eyes on. And I don’t want to see us Balkanize the language into a handful of individually fine styles which are nevertheless cognitively dissonant with one another.

Haacked May 26, 2007 at 1:24 am

I fail to see how this: 20.Minutes().Ago()

“carry within them the seeds of destruction”

Supposed we were allowed to inherit from Int32. Then that’s really no different than adding more functionality via inheritance we’re used to every day.

Bob responds: Perhaps I cranked up the hyperbole machine a little to high there, but my caution arises from the ability to add arbitrary functionality (which may or may not add value or clarity) to otherwise sealed base classes / structs, thus blurring the line between the universally available base functionality and userland code. It’s something that needs to be done both carefully and wisely, and not just “because you can”, or because you want to look like Ruby. If the latter is the primary motivation then you should be coding in Ruby, IMO. In addition, I believe you have to weigh what you’re optimizing for (say, a more elegant and self-evident solution to a particular problem domain) against the trade-offs (domain-specific APIs that are not as clearly separated from the base language functionality — or for that matter, from the BCL itself — and that will require additional ramp-up time for developers new to the solution).

Using wisdom in design is something we should do everywhere, but doubly so when we start extending BCL functionality.

I’m not sure I’d go so far as to say Microsoft shouldn’t have let this particular genie out of the bottle — there are things about the concept that strongly appeal to me, especially since we can’t really do mixins or other forms of MI on those rare occasions it might be useful — but pragmatically, what’s done is done and now we need to caution people not to go nutso with it. IMO, using it purely to create nifty, cool semantics may not be a good enough reason. Some will disagree with this point of view, and that’s fine … I just hope to get people to consider that, like any other technological capability, it doesn’t operate in a vacuum without side effects.

Haacked May 27, 2007 at 12:04 am

Well said. As you said, with every feature, the important thing is to use it wisely and not abuse it. Encouraging caution to temper the excitement is definitely laudable.

However, I’m still of the opinion that using extension methods to try and create more readable code is not merely “nifty , cool”, but important.

The challenge of developing software is not in writing code. The challenge is in reading code. Even revisiting code you wrote yourself a short time ago often presents a chasm between comprehending what is written and what your intentions were at the time. Anything we can do to bridge that gap is worthwhile.

Bob responds: I agree 110% with you, particularly your last paragraph. I have always been a little twisted in that I find, for example, ternary operators not at all less readable than if/else blocks, but I have to grant that, for instance, “DateTime.Today.FirstOfMonth” would be easier to follow than “DateTime.Today.AddDays(1 – DateTime.Today.Days)” or even “new DateTime(DateTime.Today.Year,DateTime.Today.Month,1)”. So long as it’s self-evident, I’m okay with it, but I would also hate to see a developer lost in the absence of their favorite extension library. It’s the same reason why the VB.NET “My” namespace is a mixed blessing. Yeah, it’s easier, but it can also be a crutch that avoids deeper understanding.

Leave a Comment

Previous post:

Next post: