Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
Designing With Lambdas - Part I

When our programming language of choice gets a new feature, it's usually not that hard to start using that feature right away from a consumer's point of view.

I could use the introduction of generics in .Net 2.0 as an example. When I wrote my first C# 2.0 piece of code, it already made use of the existing generic classes and methods, especially the ones in the System.Collections.Generic namespace such as List<T> and Dictionary<TKey,TValue>.

But it took a little more time until I learned how to design my own classes offering generic functionality. Reaching the balance of when to create generic classes, when to create generic methods, or when not to use generics only comes with some exercise.

I think this will be the case with lambdas for many people, including myself. Detecting opportunities to apply lambdas can make all the difference between a class that is a joy to use and one that is just the same old thing.

Processing lines in a file

My first example will be a more concise and less error-prone way of processing lines in a text file. Consider this hopefully familiar piece of code.

using(StreamReader rd = File.OpenText("Data.txt"))
{
	string line = rd.ReadLine();
	while(line != null)
	{
		DoSomething(line);
		// do more stuff with the line text

		//move on
		line = rd.ReadLine();
	}
}

How many times have you written something like this over and over? I know I did. If I were to compare the various times I implemented this, I would probably notice that the only thing that is different is the logic inside the while block. This should be a clue that a delegate or lambda could help make this pattern reusable.

But how do we create a reusable method that performs this common task without providing the logic inside the while? The last paragraph gave away the answer: delegates.

Let's create a helper class with a method to encapsulate the pattern at hand.

public static class FileUtil
{
	public static void EachLine(string fileName, Action<string> process)
	{
		using(StreamReader rd = File.OpenText(fileName))
		{
			string line = rd.ReadLine();
			while(line != null)
			{
				process(line);
				line = rd.ReadLine();
			}
		}
	}
}

The body of the EachLine method is almost the same as the original implementation we started with. The difference, as expected, is that we replaced the DoSomething(line) with a call to process, which is a delegate of type Action<string>, meaning that it expects a function that accepts a single parameter of type string and does not have a return value.

Using our new method, we can rewrite the original example like this.

FileUtil.EachLine("Data.txt", line => DoSomething(line));

Not bad. In this particular case, because we are just forwarding the line parameter to DoSomething, the call can be further simplified taking advantage of C#'s new shortened delegate creation syntax.

FileUtil.EachLine("Data.txt", DoSomething );

There you have it. Hopefully this assists someone in their journey in this new lambda thing.


Posted 04-12-2008 4:25 PM by sergiopereira

[Advertisement]

Comments

Derik Whittaker wrote re: Designing With Lambdas - Part I
on 04-12-2008 7:13 PM

This is a nice example, but is really no different than using a delegate.

sergiopereira wrote re: Designing With Lambdas - Part I
on 04-12-2008 7:29 PM

@Derik

I hope not :) Lambdas are implemented as delegates in .Net after all. I think the key advantage of lambdas over delegates is the simplicity of the call. We all knew how to use delegates since .Net 1.0, but we don't see a lot of .Net 1 or even .Net 2 that used delegates the way we are starting to see with .Net 3.5.

El Guapo wrote re: Designing With Lambdas - Part I
on 04-13-2008 12:48 AM

This is really a major paradigm shift and I think this post captures it very well actually.  I always implement this example with something like this:

public abstract class LineReader

{

 public void Execute()

 {

   using(StreamReader rd = File.OpenText("Data.txt"))  

   {  

     string line = rd.ReadLine();  

     while(line != null)  

     {  

         DoSomething(line);  

         // do more stuff with the line text  

         //move on  

         line = rd.ReadLine();  

     }  

   protected abstract void DoSomething(string line);  

 }  

}

And then derive classes from LineReader when I need to do various things with text files.

This is very C++ish and somewhat old school now. I used to think this was just so brilliant... things are really changing and I'm not sure it's for the better. In my opinion the old-school object oriented method is still easier to read and maintain.

Dew Drop - April 13, 2008 | Alvin Ashcraft's Morning Dew wrote Dew Drop - April 13, 2008 | Alvin Ashcraft's Morning Dew
on 04-13-2008 8:10 AM

Pingback from  Dew Drop - April 13, 2008 | Alvin Ashcraft's Morning Dew

rascunho » Blog Archive » links for 2008-04-13 wrote rascunho &raquo; Blog Archive &raquo; links for 2008-04-13
on 04-13-2008 4:38 PM

Pingback from  rascunho  &raquo; Blog Archive   &raquo; links for 2008-04-13

Paul Kinlan’s Development Blog » Development Link and Comment Goodness: 14th April 2008 wrote Paul Kinlan&#8217;s Development Blog &raquo; Development Link and Comment Goodness: 14th April 2008
on 04-14-2008 5:23 AM

Pingback from  Paul Kinlan&#8217;s Development Blog &raquo; Development Link and Comment Goodness: 14th April 2008

Sergio Pereira wrote Designing With Lambdas - Part II
on 04-14-2008 11:34 PM

In my last post I went through a very simple example of applying lambdas to achieve more DRY . In this

Reflective Perspective - Chris Alcock » The Morning Brew #73 wrote Reflective Perspective - Chris Alcock &raquo; The Morning Brew #73
on 04-15-2008 2:47 AM

Pingback from  Reflective Perspective - Chris Alcock  &raquo; The Morning Brew #73

Designing With Lambdas - Part I - Sergio Pereira « Noocyte’s Weblog wrote Designing With Lambdas - Part I - Sergio Pereira &laquo; Noocyte&#8217;s Weblog
on 04-21-2008 9:46 AM

Pingback from  Designing With Lambdas - Part I - Sergio Pereira &laquo; Noocyte&#8217;s Weblog

Sergio Pereira wrote Designing With Lambdas - Part III
on 04-29-2008 2:58 PM

In the previous two installment of the series we discussed how we can use lambdas to encapsulate more

Waterbreath wrote re: Designing With Lambdas - Part I
on 05-15-2008 11:31 AM

First some setup....

public static class Visitor

{

   // Deferred execution.

   public static IEnumerable<T> Visit<T>(this IEnumerable<T> lhs, Action<T> f)

   {

       foreach (T t in lhs)

       {

f(t);

           yield return t;

       }

   }

   // Manifest the collection, including execution of all deferred lambdas, by walking the iterator.

   public static void Evaluate<X>(this IEnumerable<X> lhs)

   {

       foreach (X x in lhs);

   }

}

public static class FileUtil  

{  

   public static IEnumerable<String> ReadLines(this StreamReader reader)

   {

       string line = rd.ReadLine();  

       while(line != null)  

       {

           yield return line;

           line = rd.ReadLine();

       }

   }

}  

And then to use it....

using(StreamReader rd = File.OpenText(fileName))  

{

   rd.ReadLines()

       .Visit(process)

.Evaluate();

}

Waterbreath wrote re: Designing With Lambdas - Part I
on 05-15-2008 11:42 AM

Arrrgh!

Sorry for the terrible formatting.  I copied that from notepad and it still ended up doublespaced.  Honest!

I also dropped my "intro" paragraph because the first time I submitted it failed, and I forgot to retype, so here it is...

I prefer to extract the visitor pattern into a couple of extension methods for IEnumerable<T>.  I'm super excited about this and can't believe MS didn't include something like it right there in .NET 3.0 to begin with.  Having a visit function like that offers the potential to turn essentially every explicit "foreach" into a simple function call passing a lambda or function.  Which I think is awesome because it reduces "syntax noise" (weblog.raganwald.com/.../abbreviation-accidental-complexity-and.html).

About The CodeBetter.Com Blog Network
CodeBetter.Com FAQ

Our Mission

Advertisers should contact Brendan

Subscribe
Google Reader or Homepage

del.icio.us CodeBetter.com Latest Items
Add to My Yahoo!
Subscribe with Bloglines
Subscribe in NewsGator Online
Subscribe with myFeedster
Add to My AOL
Furl CodeBetter.com Latest Items
Subscribe in Rojo

Member Projects
DimeCasts.Net - Derik Whittaker

Friends of Devlicio.us
Red-Gate Tools For SQL and .NET

NDepend

SlickEdit
 
SmartInspect .NET Logging
NGEDIT: ViEmu and Codekana
LiteAccounting.Com
DevExpress
Fixx
NHibernate Profiler
Unfuddle
Balsamiq Mockups
Scrumy
JetBrains - ReSharper
Umbraco
NServiceBus
RavenDb
Web Sequence Diagrams
Ducksboard<-- NEW Friend!

 



Site Copyright © 2007 CodeBetter.Com
Content Copyright Individual Bloggers

 

Community Server (Commercial Edition)