CodeBetter.Com
CodeBetter.Com
RSS 2.0 via Feedburner
           Do you Twitter? Follow us @CodeBetter

Jeremy D. Miller -- The Shade Tree Developer

Under the hood and working with .Net, TDD, Software Design, and Agile Stuff

I used my first closure in C# 2.0!

Okay, it's lame, but still:

   53                 return Array.Find<ISystemUnderTest>(

   54                     _systems,

   55                     delegate(ISystemUnderTest system)

   56                         {

   57                             return system.Name == systemName;

   58                         });

where _systems is an array of ISystemUnderTest[] and systemName was an argument to the method that contains this code.

Somebody will have to correct me, but I think the Ruby equivalent (they call them "blocks") would look like this:

systems.Find (|system| {system.name == name}) 

Ruby is definitely cleaner, but I'm happy to have some of this stuff in C# now.  I was playing quite a bit with Prototype in Javascript a couple months back and got hooked on the functional idioms like this method below:

	table.drawPage = function(iterator, columns){
this.clear();

columns.each( function(column){
this.createHeader(column);
}.bind(this));


while (subject = iterator.next()){
this.drawRow(columns, subject);
}
}

The code "columns.each( function(column){ ..." is the closure.  This calls the current class's createHeader() method on each member of the columns array.  Before you run off and try this  in Javascript, it's Prototype that extends the Javascript Array object with a bunch of "Ruby-isms" like this.  You'll need to grab the Prototype library first.

Check out Martin Fowler's explanation of closures for an explanation.  I'm really looking forward to  the C# 3.0 features now.  I'm skeptical of much of the Microsoft canon, but I'm sincerely in awe of Anders Hejlsberg. 

 

 

 



Comments

Sam Smoot said:

Your Ruby example is close, but blocks are always the last parameter to a method, so the binding parse-wise has them appearing outside of the parenthesis. Also, parameters passed to a block are defined in the block. So:

systems.find() { |system| system.name == name }

(Parenthesis used for clarity)

In your example Ruby would probably see the opening curly-brace and expect a hash-literal instead of a block.

This syntax is consistent with lambdas (a function to declare a block) and Procs (a class representing a block), so it gets reinforced and makes it a little easier to remember.

So we could also write it like:

condition = lambda { |system| system.name == name }

systems.find(&condition) # Use the "&" to indicate a block-argument.

Or:

condition = Proc.new { |system| system.name == name }

systems.find(&condition)

Of course Array#find just returns the item you're looking for. Which is known ahead of time in this case. So I'm assuming this is just a simplified example. If not, I would suggest using Array#index or Array#include? instead.

A couple things to keep in mind with regards to the Prototype library: It's iterators are very slow. Hopefully most of the time it shouldn't matter. When it does, stick to a traditional for() loop though. Also, if you're iterating over hashes like so:

for(var key in something) {

 alert(key);

}

You'll get the decorated methods too. Which is no fun. You'll want to use this instead:

for(var key in something) {

 if(typeof something[key] == 'function') { continue; }

 alert(key);

}

Anyways, nice post. :-)

# October 16, 2006 12:36 AM

Jeremy D. Miller said:

Thanks for the tips Sam.  I'm a bit of a newbie in these areas.

# October 16, 2006 6:14 AM

karl said:

It's a bit cleaner with a generic, since you don't have to supply the _systems parameter:

_systems.Find(delegate(ISystemUnderTest system)

                        {

                           return string.Compare(system.Name, systemName, true) == 0;

                        }

                    );

Thank god for Resharper's formatting of these things :)

# October 16, 2006 6:57 AM

Brendan Tompkins said:

I started using this syntax too a couple of weeks ago... But I'm still not sure what it's called.. Is the .Find(delegate.. sytax a closure, or just a delegate?

# October 16, 2006 9:39 AM

Sam Smoot said:

I hope I've got the syntax right. I don't have a Windows machine to test with right now:

<code>

public void Main() {

Console.WriteLine("c# supports closures? {0}", (GetClosure()() == true));

}

Delegate GetClosure() {

bool capture = true;

return delegate() {

return capture;

};

}

</code>

So, what determines a Closure is wether it captures the value of variables that would have otherwise gone out of scope.

# October 16, 2006 10:09 AM

Duncan Godwin said:

C# 3.0 it becomes nicer:

return Array.Find<ISystemUnderTest>(_systems,

                        system => system.Name == systemName);

Can't wait :)

# October 16, 2006 2:58 PM

Sam Smoot said:

Actually, I think my c# example is off WRT the return statement.

Maybe it's just me, but I *HATE* the new lambda syntax in c#3. It's inflexible. In Ruby you can have a block of any length, but c#3's syntax limits you to a single expression as far as I can tell. Which is more of a nifty toy feature than anything since you could just do the same thing with Enumerable methods.

So now, in addition to event, Delegate, and delegate we get a new syntax for lambdas. Ruby does all this with one syntax. Or Python. Or pick-your-language. Messy.

# October 16, 2006 7:25 PM

Jeremy D. Miller said:

I agree with you Sam, but it's still nice to see these features coming in a mainstream, statically typed language.  I know *you* get paid to write Ruby, but the rest of us (as I sit here in my No Fluff, Just Stuff, i.e. Ruby reeducation camp, t-shirt) can only dream.

# October 16, 2006 7:29 PM

Jason Haley said:

# October 16, 2006 9:49 PM

Sam Smoot said:

Heh, I wish. I've been lucky enough to code in Ruby and .NET in spurts, but I spend 90% of my time these days trying to bend ASP Classic to my will. At least at work. :-)

I agree it's nice to c# getting extra features though. I'm just a little concerned about the fragmentation.

# October 16, 2006 10:01 PM

Jeremy D. Miller said:

Ruby to spaghetti code ASP classic?  Rough dude.  There has never in the history of mankind been a nontrivial ASP classic application that wasn't a big ball of mud.

# October 17, 2006 7:36 AM

Oren Ellenbogen said:

I love delegates & anonymous methods! really! you could create great "templates" and provide some high-level API for your developers which really cuts down repetitive code. I even did a lecture in the C# User Group (in Israel) about this subject:

http://www.lnbogen.com/SlidesDemosFromMyCodeTemplatingPresentation.aspx

# November 25, 2006 10:19 AM

Leave a Comment

(required)  
(optional)
(required)  

Enter the numbers above:
Add

About Jeremy D. Miller

Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy previously worked as a systems architect building mission critical supply chain software for a Fortune 100 company and learned agile development practices as a .Net consultant at ThoughtWorks, one of the pioneers of agile development. Jeremy is the author of the open source StructureMap (http://structuremap.sourceforge.net) tool for Dependency Injection with .Net and the forthcoming StoryTeller (http://storyteller.tigris.org) tool for supercharged FIT testing in .Net. Jeremy's thoughts on just about everything software related can be found on his weblog "The Shade Tree Developer" at http://codebetter.com/blogs/jeremy.miller, part of the popular CodeBetter site. Jeremy is a Microsoft MVP for C#. Check out Devlicio.us!

This Blog

Syndication

News

All opinions expressed here constitute my (Jeremy D. Miller's) personal opinion, and do not necessarily represent the opinion of any other organization or person, including (but not limited to) my fellow employees, my employer, its clients or their agents.

About Me

"Best Of" Compendium

StructureMap (Dependency Injection for .Net)

StoryTeller (Supercharged Fit)

Build your own Cab

TestDriven

MVP