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

Subversion Turns 1.5

Given the number of developers using Subversion, I'm surprised that no one on my blogroll has mentioned the new Subversion clients released in the last few weeks. Subversion, TortoiseSVN, and VisualSVN have all synchronized their version numbers on v1.5. I'll talk about TortoiseSVN and Subversion changes. VisualSVN has some minor enhancements that basically expose the features introduced by Subversion 1.5. I'll leave you to investigate them yourself.

TortoiseSVN

Let's talk TortoiseSVN... You can get the new client from here. N.B. If you're running 64-bit Windows (XP, Vista, or Server 2003/2008), make sure you grab the 64-bit installer. Shell extensions run directly inside Windows Explorer, which on 64-bit Windows is a 64-bit process. So you don't get any WoW (Windows-on-Windows) goodness that allows 32-bit executables to run on 64-bit Windows.

New Overlays

The most noticeable change is the new overlay icons.

image

Unversioned and ignored files now have their own overlays, which I find especially useful.  The problem in the past was that Windows only has 12 overlay slots available.  These slots could be easily exhausted if you had multiple shell extensions installed, such as TortoiseSVN and TortoiseCVS.  Tortoise clients now have a common overlay handler, which somewhat mitigates this problem.

image

Delete Unversioned Files

Over time, working copies tend to get crufty - at least mine do. I end up having extra unversioned files and directories - from tools, builds, half-implemented refactorings that you think better of - littering your working copy. Every once in awhile, I would just grab a clean working copy and delete the old. I then went to the trouble of creating PowerShell script to clean up my working copy. Now TortoiseSVN 1.5 includes this feature. Simply SHIFT-right click in your working copy and select "Delete unversioned items" from the context menu.  N.B. This option only appears if you hold down SHIFT.

image

Other Improvements

The repository browser has also been completely reworked.  It now shows a two pane view similar to Windows Explorer.

image

The revision graph has also been rewritten and is much easier to use.

image

Client-side caching has been improved, making TortoiseSVN more responsive. Merging has improved. Changelists have been added. Lots of new features. You can read the release notes for more information.

Subversion

Subversion has made a lot improvements, which can be found in the release notes. If you're just running TortoiseSVN, you don't need to install the Subversion binaries. TortoiseSVN includes the SVN libraries. You only need the Subversion client and/or server if:

  1. You want to use Subversion from the command line via svn.exe and/or svnadmin.exe either directly or in scripts.
  2. You are running a server using svnserve (svn://) or Apache (http:// or https://).

You can download the Windows client and/or server from a few different places, each with advantages and disadvantages:

  • CollabNet - On the positive side, the MSI installer is quick to get you up and running. It adds svn.exe to your path and, if you install the server, you can select between svnserve.exe (svn://) and Apache (http:// or https://) easily. On the downside, you have to register on the CollabNet site and the downloaded binaries do not include support for Berkley DB, only FSFS. FSFS is the default for new repositories, but if you've got some older repositories around, they're probably BDB. The CollabNet binaries complain bitterly about BDB repositories: "svnadmin: Failed to load module for FS type 'bdb'". Honestly I would recommend staying away from this package.
  • Tigris - Scroll down to svn-win32-1.5.0.zip and grab that. It includes both FSFS and BDB support, but you're on your own configuring svnserve.exe. It's not that hard and I document the steps here. This package is great if you just want to run svnserve.exe to access your repositories via svn://. If you want to run Apache to enable access your repositories over http:// and https://, you're on your own to download and configure Apache. If you want to do that, then I recommend...
  • VisualSVN Server - Although VisualSVN (the Visual Studio add-in) is a commercial product, VisualSVN Server is completely free. This is the easiest way to get a Subversion server up and running with Apache. You can go from a clean Windows box to a working Subversion server in under 10 minutes. As an added bonus, it includes a MMC management console.

Upgrading the Repository Format (optional)

Although Subversion 1.5 can work with older repository formats, some of the new features, such as merge tracking, require you to upgrade your repository to the latest format. (See "Compatbility Concerns" in the release notes for full information regarding required client, server, and repository versions for various features.) Subversion will not upgrade your repository automatically. If you want to use the new features requiring a repository upgrade, you must run the following command:

svnadmin upgrade <PATH_TO_REPO>

where <PATH_TO_REPO> is the physical path and not a URL.

If you need to upgrade a lot of repositories and you've got PowerShell installed, you can do the following (assuming your repository root is c:\SrcRepos):

cd \SrcRepos
dir -name | foreach { svnadmin upgrade $_ }

Cyrus SASL and NTLM

TortoiseSVN and svnserve now include Cyrus SASL (Simple Authentication and Security Layer) support, which allows you to use a variety of authentication/encryption mechanisms, most importantly for Windows users - NTLM and Kerberos. Subversion clients and servers prior to 1.5 only support ANONYMOUS and CRAM-MD5. You'll need to be running v1.5 on both sides of the wire to use the other protocols. The ZIP package from Tigris includes NTLM, but not Kerberos. If you want to use Kerberos, you'll have to download saslGSSAPI.dll and add it to your sasl-plugins directory.

WARNING: I spent the better part of an afternoon trying to get svnserve.exe authenticating against the local Security Account Metabase (SAM) without success. (i.e. Using local Windows accounts to authenticate Subversion users.) The documentation is sparse to non-existent. I was able to get SASL to read its configuration and load the NTLM plug-in, but I could never successfully authenticate. Even with the correct username/password, it just prompted me again. It could be a problem with SASL defaulting to NTLMv1, which Vista disables by default for security reasons. If I figure out how to make this work, I'll post a solution...

Get Your Func On

I've noticed that I have a 2 step pattern for learning new framework or language features. I'm guessing this is pretty typical for most people. First, I'll use the feature within framework classes or 3rd party ddls. Then I'll leverage it more directly within my own code. What's surprising to me is the length of time which occurs between step 1 and step 2.

Take generics for example. Back in the 1.x days, I wrote a ton of repetitive classes that inherited from CollectionBase. So when 2.0 came out, I immediately and aggressively started to use generic collections. However, it was quite some time later (a year?) until I wrote my own class that leveraged them directly. Today, I don't write a new generic class every day, but I do consider them an important part of my toolbox and kinda wonder what took me so long to take them up.

I have a feeling that many developers are in the same boat - it's easy to consume code that implements new features, but not so easy to grasp how to implement those same features ourselves.

As it turns out, the other day, I had another such ah-hah moment with the System.Func generic delegate. Like me, you've probably consumed it often, or at least one of its cousins: System.Action and System.Predicate. I thought I'd show how I used it, in hopes that it might open up some possibilities for you.

Ovewview

First though, a brief overview. The three delegates above are essentially shortcuts that save you from having to write your own common delegate. The most common one is probably Predicate<T>, which returns a boolean. Predicte<T> is used extensively by the List<T> and Array classes. The most obvious is the Exist method:

List<string> roles = user.Roles;
if (roles.Exists(delegate(string r) { return r == "admin";}))
{
   //do something
}

or the lambda version (which I much prefer)

if (role.Exists(r => r == "admin))
{
}

Func<T> is a lot like Predicate, but instead of returning a boolean it returns T. Also, Func<T> has multiple overloads that let you pass 0 to 4 input parameters into the delegate. Action<T> is like Func<T> except it doesn't return anything - it does an action.

Code Decoupling

So, how can you make use of these within your own code? Well, here's what I did. First, I'm a big proponent of caching, as well as a big fan of unit testing. However, the two don't easily go hand-in-hand because Microsoft doesn't provide an interface to their built-in cache, which leads to tight coupling (which of course makes it difficult to change caching implementation down the road, and impossible to unit test). The first thing to do is create your own interface, a simple start might look like:

public interface ICacheManager
{
   T Get<T>(string key);
   void Insert(string key, object value);
}

Next comes our first implementation:

public class InMemoryCacheManager : ICacheManager
{
    public T Get<T>(string key)
    {
        return (T) HttpRuntime.Cache.Get(key);
    }
    public void Insert(string key, object value)
    {
         HttpRuntime.Cache.Insert(key, value);
    }
}

Func Fights Repitition

So, what does all this have to do with System.Func? Well, the above code is used in a very repetitive manner: get the value from the cache, if it's null, load it from somewhere and put it back in the cache. For example:

public User GetUserFromId(int userId)
{
    ICacheManager cache = CacheFactory.GetInstance;
    string cacheKey = string.Format("User.by_id.{0}", userId);
    User user = cache.Get(cacheKey);
    if (user == null)
    {
       user = _dataStore.GetUserFromId(userId);
       cache.Insert(cacheKey, user);
    }
   return user;
}

After a year or so of writing code like this, I figured there must be a better way, which of course is where Func comes in. Ideally, we'd like to get the value, and provide our callback code all at once. So, let's change our interface:

public interface ICacheManager
{
   T Get<T>(string key, Func<T> callback);
   void Insert(string key, object value);
}

The second parameter is the delegate we'll want to execute if Get returns null. Of course our delegate will return the same type (T) as Get would - just like in the above case where we expect a User from both Get and our data store. Here's the actual implementation:

public T Get<T> (string key, Func<T> callback)
{
   T item = (T) HttpRuntime.Cache.Get(key);
   if (item == null)
   {
       item = callback();
       Insert(key, item);
   }
   return item;
}

How do we use the above code?

public User GetUserFromId(int userId)
{
   return CacheFactory.GetInstance.Get(string.Format("User.by_id.{0}", userId), 
                                                                () => _dataStore.GetUserFromId(userId));
}

I know the () => syntax might be intimidating (especially if you aren't familiar with lambdas), but all it is is a parameterless delegate.

Of course, this system can easily be expanded to add additional caching instructions (absolute/sliding expiries, dependencies and so on) via overloaded Get<T> and Insert members.

(I just noticed this example also highlights how to use generics within your own code too!)

Composite Application Guidance is Live

Before I go any further, we shipped! :-)

Links:

What's in the box

Here's an overview of what you'll find

image

At the core is the Stock Trader Reference Implementation.

RIScreenshots_small.png

This app is a composite application built in WPF. In it you'll find design patterns, concepts and techniques you can add to your arsenal.

Supporting the RI, you'll find a library which aids in implementing the patterns. The library is light, really light and that's deliberate. We harvested it out of the RI rather than building it first and throwing an app on top. We built it to work with your existing infrastructure rather than you having to build from scratch on top of it. We built it to work 100% with WPF rather than retrofitting WinForm concepts into a WPF world.

Around the RI, you'll find comprehensive documentation (see the diagram above) in which you'll see the major design concepts and patterns are for building composites such as the RI. You can use this knowledge to build your own implementations if you decide that ours is not right for you. You'll also learn how we've decided to implement those patterns and concepts and why. You'll see how to use the pieces separately, or put them together in a coherent fashion to form the baseline architecture you see below.

image

Finally you'll find a set of quickstarts and how-tos to help you get ramped up on the concepts.

A little history

If you'd have asked me 12 months ago, I would have said this day would have never come. Around that time we had just announced that we had no further plans to do anything in the CAB space. Instead our goal was to lead everyone toward a mythical creature called Acropolis. With Acropolis on the way it didn't make sense for us to continue. Then by some strange twist of fate, Acropolis was folded into future versions of the framework. This opened the door for us to address building Composite applications for WPF. Once we had the green light to go ahead, we had a tough decision to make, take CAB forward to WPF or start over. We chose to start over. 8 months later, we've incorporated tons of community feedback, built a new set of guidance specifically for building Composite applications in WPF. As it goes out the door, we're very happy we stuck to our guns on that decision.

The Team

We couldn't have done it alone. In addition to a fantastic, and extremely focused team including Brian Noyes from IDesign, Adam Calderon from Interknowlogy, Southworks and Infosys we had a large set of advisors. Across Microsoft, we had help from several product teams including WPF (Henry Hahn,Ivo Manlov,John Gossman,Mike Hillberg,Rob Relyea), UIFX (Brad Abrams and David Hill), DPE (Jaime Rodriguez, Karsten Junszewski, Jared Bienz, Mark Feinholz), and App Dev Consulting's Josh Twist. Combine this with an amazing committed group of partners (Infragistics), industry experts and advisors including David Platt,Jeremy Miller, Ohad Israeli,Oren Eini, Rob Eisenberg, Szymon Kobalczyk,Udi Dahan, and Ward Bell. This is just a sampling, the full list is below

Bil Simser, Brad Abrams (Microsoft Corporation), Chad Myers, David S Platt (Rolling Thunder Computing, Inc.), Derek Greer, Ian Ellison-Taylor (Microsoft Corporation), Ivo Manolov (Microsoft Corporation), Jamie Rodriguez (Microsoft Corporation), Jeremy D. Miller (Dovetail Software), Josh Twist (Microsoft Corporation), Matt Smith (AltiMotion Corporation), Mark Tucker (JDA Software Group, Inc.), Michael D. Brown (Software Engineering Professionals, Inc.), Michael Kenyon (IHS, Inc.), Michael Sparks (RDA Corp), Ohad Israeli (Hewlett-Packard), Oren Eini (aka Ayende Rahien), Peter Lindes (The Church of Jesus Christ of Latter-day Saints), Rob Eisenberg (Blue Spire Consulting, Inc.), Shanku Niyogi (Microsoft Corporation), Scott Bellware, Szymon Kobalczyk (InterKnowlogy), Udi Dahan (The Software Simplist), Varghese John (UBS), Ward Bell (IdeaBlade)

Final thoughts

For me, this has been an incredible journey. I've had the pleasure of working with the most talented individuals inside and outside of Microsoft than I have to date. It just doesn't get any better than this! Thank you to everyone who has made this possible!

As Soma likes to say Namaste!

RockNUG Meeting - 7/9/2008 - Functional C#

Next week I will be presenting a lightning talk at the next Rockville .NET Users Group (RockNUG) on Functional C#.  I've talked about this topic quite a bit recently on a couple of threads now:
In this talk I hope to cover some of the basics including:
  • Currying
  • Filter
  • Map
  • Option Types
  • Tuples
  • Folding and Unfolding
  • Recursion
  • Lazy Evaluation
  • And more...
I know it's quite aggressive for such a short timeframe, and I may cut some of them due to how many questions I get.  This will be a continuation of my talk at the NoVA Code Camp back in May.  At the end, I hope to post my code at least.  I haven't published my slides due to me not being exactly happy with them yet.  I'll post a wrapup afterwards.

Anyhow, here are the details:

Date/Time:
Wednesday, July 9, 2008 - 6:30-9:00 PM

Location:
Montgomery College, Rockville
Humanities Building - Room 103
Rockville, MD
Directions

Hope to see you there!

Holiday postcard, Turkish internet cafe's

Almost holiday. To get in the mood two holiday postcards shot last holiday in Bodrum, Turkey.

Colorfull as everything in Turkey. I didn't check inside, promised myself to stay off line for the entire holiday to read myself into deeper insight. The local ATM's did promise a smooth and fast net.

This is also an answer to a somewhat enigmatic Turkish comment on a picture of Charles Petzold. Where is the man ? Right here !

Enjoy your holidays !

Showing some support for LINQ to SQL

While I have finished my series on LINQ to SQL I wanted to talk about some of the reaction. In his summary post of 30 June Roger Jennings mentions his concerns that because the SQL Server Data Programmability group, who are bringing us Entity Framework v1, now owns LINQ to SQL we will not see the kind of development I asked for in my last post of my Architecting LINQ to SQL series. Indeed Matt Warren's comment in this post, that the provider model for LINQ to SQL was disabled before release is troubling for what it implies about internal politics over data access strategies in Redmond and might confirm concerns I had a long time ago.  Looking at the the Data Platform team's blogs and site, LINQ to SQL seems almost forgotten.

I would like to see MS give this product the support it deserves. I would like to see a commitment from the Data Platform team to stop its focus on talking LINQ to SQL down as a RAD tool and tallking up its advantages for use in the OO approaches to software development. For example  I would like to see the Data Platform team talking about LINQ to SQL's support for POCO strategies, lazy loading, etc. and pointing out to customers who request those features. There needs to be more acknowledgement that if you want them you should consider LINQ to SQL. Right now their only response is to repeat that those features will be in Version 2 of the EF. Well, an MS ORM supports those features today, you should point that out to your customers, and give advice on how to achieve it. As of now, in my opinion, LINQ to SQL is their best development tool for OO an approach to development and they need to reflect its strengths in the advice they give, not just focus on its weaknesses when compared to EF. 

Martin Fowler posted some time ago about different schools of software development. Perhaps one solution for the conflict over the future of these tools is for MS to accept that it has (at least) two audiences and build a product for the OO folks and one for the data-first folks. In that case LINQ to SQL would be a better start for the OO folks because it already contains so much of what they need, it may represent a better starting point for supporting them.

People feel sorry for the Entity Framework team for the criticism in the open letter. For my part I feel sympathy for the LINQ to SQL team, who fell foul of product strategy decisions with ObjectSpaces and seem to have done so again. Considering how well they understood the OO approaches we wanted, unlike the EF team, the team are unsung for their efforts. The Alt.Net community in particular should give them wider support for having, unlike the Entity Framework team, recognized the needs of those developers taking an OO approach to development. it does not give us everything, but credit where it is due.

Today, while I would not recommend using the Entity Framework I would recommend looking at LINQ to SQL. Everything needs evaluation for your own needs, but unlike EF, LINQ to SQL is a better contender for OO approaches today.

Sasha points out when looking at how LINQ to SQL is suprising people who had been misinformed as to what if offered and how we should use it, the noise in the blogsphere from Entity Framework supporters seems to have drowned out the value of LINQ to SQL as an ORM. Indeed I believe the Data Team's own pitching of LINQ to SQL as a RAD tool is an underestimates the product.

As a community, as people begin to realize the suprising power of LINQ to SQL, I would like to see us dispel many of the myths that seem to have grown up around that product. I would like to see us put pressure on the Data Platform team to provide the support for LINQ to SQL that we want going forward. Community reaction is everything and if the LINQ to SQL community remains silent in the face of the more vocal, but probably less numerous, EF community, we won't get the product we deserve.


Define Recursion - See Recursion

Lately, I've noticed a few blogs are doing the come back to basics post, such as Scott Hanselman's.  I think that's an effort that should be lauded, because many have a tendency to go off on pretty advanced topics, yet not provide enough for those just starting to get the full context.  So, with that, I'm going to dig into one piece of programming that should have been ingrained should you have been a CS major in college or at least took some courses.

Recursion

Recursion is one of those basic topics that come up time and time again as one of the core topics.  It's not as often talked about in the imperative and object oriented world, but in the functional programming world, it matters a whole bunch.  Not only to be able to describe what it is, but the benefits, and where you might be able to break your problem down into using it.

So, before we get too far, what exactly is it, and how do we get there?  Basically recursion is to allow a function to call itself repeatedly during the body of that function.  Most imperative languages from the C world use for loops, while loops and so on, so many times recursion isn't needed.  Functional languages such as F#, allow for recursion, but makes them a special designation to enforce its behaviors. 

When coming to a place such as Microsoft, understanding these concepts are key.  Chances are you may get asked some of these questions, because people like me, when walking through complex structures, use recursive algorithms.  It's a nice tool to have in the toolbox.

Let's first look at an example not using recursion, then move towards recursion.  First start off with a pretty obvious one in computing a factorial:

public static int Factorial(int n)
{
    int result = 1;

    for (int i = 1; i <= n; i++)
        result *= i;

    return result;
}

To me, that's pretty horridly imperative.  We can make the code much more concise through the use of recursion and not mutate state during the operation.  With the proper attention of course to decrementing the counter so that we don't get into infinite loops.  An important lesson to learn is to not recurse infinitely, but in a controlled manner towards termination through a technique called "Well Founded Recursion".  Let's rewrite this to a much more manageable way:

C#
public static int Factorial(int n)
{
    if (n <= 1) // Exit condition
        return 1;

    return n * Factorial(n - 1);
}

F#
let rec factorial n =
  if n <= 1 then 1 else n * factorial (n - 1)

The basic idea is to break down your problems into smaller instances of the same problem.  Sometimes, the last thing we do in this function is return the recursion of the function.  This is called "Tail Recursion".  Below is a simple example of tail recursion:

let rec last l =
  match l with
  | [] -> invalid_arg "l"
  | [head] -> head
  | head :: tail -> last tail

The above sample will ultimately give me the last item in a list since F# has pointers to the head of the list, we need to get the last one.  We'll get more into tail recursion in the next post, but I thought I'd introduce it now.  It's very important as well to know.

Let's take another example, this time walking a directory structure to lazily display all files in a directory.  Of course we can note that the Directory.GetFiles already has the capability of getting all files in all folders, but for this exercise, let's pretend it doesn't exist.  How might we do this?  Let's try the lazy approach the first time around through IEnumerable<string>.

C#
public static IEnumerable<string> GetFiles(string rootPath)
{
    foreach(var file in Directory.GetFiles(rootPath))
        yield return file;
    foreach (var directory in Directory.GetDirectories(rootPath))
        foreach (var file in GetFiles(directory))
            yield return file;
}

F#
let rec getFiles rootFolder =
    seq {
          for file in Directory.GetFiles(rootFolder) -> file
          for dir in Directory.GetDirectories(rootFolder) ->> getFiles dir
        }

What this allows me to do is recurse through a given directory hierarchy by first grabbing all the files and then going through a tail recursion through all the subdirectories.  The F# way is a bit more concise through the use of Sequence Workflows, which I'll get to at another time.  If you understand anything about F#, understanding workflows is by far one of the most important.

Mututal Recursion

Another interesting way to express recursion is to define them simultaneously by separating the definitions.  This allows the functions to play off each other and work towards a deterministic end.  The cannonical example of this is the odd/even sample.  Let's walk through that quickly in both C# and F#:

C#
public static bool IsEven(int number)
{
    if (number == 0)
        return true;
    else
        return IsOdd(number - 1);
}

public static bool IsOdd(int number)
{
    if (number == 0)
        return false;
    else
        return IsEven(number - 1);
}

F#
let rec even n = (n = 0) || odd(n - 1)
  and odd n = (n <> 0) && even(n - 1)

As you can see, I decrement the counter each time and call the complement function until I reach 0 and at that point, I can determine which one hits 0 and then it becomes apparent whether it is odd or even.  F# goes a bit further to simplify this so that I can declare those functions as a pair through the use of the and keyword.  Parsing of trees is particularly useful using mutual recursion.  But just as easily, we could have done the above sequence without using recursion at all such as this:

public static bool IsEven(int number)
{
    return number % 2 == 0;
}

public static bool IsOdd(int number)
{
    return !IsEven(number);
}

So, that's not really a good example.  instead, let's look at a Hofstadter Male-Female Sequences instead. 

The pair of sequences is defined by Female(0) = 1 and Male(0) = 0 and
Female(n) = n - Male(Female(n - 1)
Male(n) = n - Female(Male(n - 1)

This is defined as the same way as before, but we recursively call in the Male to the Female and back to the male, whereas it's the opposite in the FemaleSequence method.  This is just a simple implementation of the above algorithm in our C# and F# code respectively.

C#
public static int MaleSequence(int n)
{
    if (0 == n)
        return 0;

    return n - FemaleSequence(MaleSequence(n - 1));
}

public static int FemaleSequence(int n)
{
    if (0 == n)
        return 1;

    return n - MaleSequence(FemaleSequence(n - 1));
}

F#
let rec maleSequence n = if n = 0 then 0 else n - femaleSequence(maleSequence n - 1)
  and femaleSequence n = if n = 0 then 1 else n - maleSequence(femaleSequence n - 1)

There are more examples out there, but in the mean time, there's plenty more to cover with recursion.  Next, let's cover lists.

Walking Lists

Another thing we can do with recursion is the ability to walk lists.  Most people think of lists as an ordered collection with a beginning and an end, with one right after another.  How terribly imperative if you think that way...  When we think of lists in a recursive way, we think of a list to have an item, and the rest of the list, or just an empty list.  C# and the base class library does not have this of course defined in any meaningful way, so let's look at the F# version of a list.  

module List =
  val hd: 'a list -> 'a
  val tl: 'a list -> 'a list

What that tells us is that the head item is the first, and the tail is the rest.  Let's do a quick recursion to calculate the length of a list using some pattern matching:

let rec length l =
  match l with
  | [] -> 0
  | head :: tail -> 1 + length tail

What I'm doing is pattern matching against the list.  What the pattern matching allows me to do is short circuit if it's an empty list, else, I'm splitting the head and the tail, and adding one to the length of the tail call with the tail of the list.  Let's look at another to concat a list of lists into a single list:

let listOfList = [[1;2;3;];[4;5;6;];[7;8;9]]

let rec concatList l =
  match l with
  | [] -> []
  | head :: tail -> head @ concatList tail

There is much more to cover here and I'll do that in subsequent posts.

Why Recursion?

Now that we covered some of the basics, it's time to ask the question why.  Why is recursion important and why use it?  Well, to answer that lightly, in order to walk such things as trees, directories, and so on, it's an absolute essential.  But, let's consider just a general functional programming question of why use it.

It's often the case that when people first start out with programming in F#, they are often in the imperative and OO mindset still.  That's ok since F# allows for this, but there are better ways to accomplish in the functional mindset.  Many times, people will port over their C# code directly to F# with the mutable variables or reference cells and leave an ugly mess.  Some of that can be solved with recursion.  Let's take a pretty naive example:

C#
public static void CountDown(int n)
{
    while(n > 0)
    {
        DoOperation();
        WaitSome();
        n -= 1;
    }
}

When translated directly to F# looks like this:
let countDown n =
  let mutable localN = n
  while localN > 0 do
    DoOperation()
    WaitSome()
    localN <- localN - 1

What we've had to do is use reference cells so that we could change the value of n directly.  From there, we have to use special operators to change and alias the value of n.  Not the prettiest code.  Not only that, but there is mutation galore, and I have to do extra work when creating a local iterating variable.  instead, we should focus on recursion and look at the problem slightly differently.

let rec countDown n =
    match n with
    | 0 -> 0
    | _ ->
      DoOperation()
      WaitSome()
      countDown (n - 1)

What this allows me to do is get rid of the local mutables, but also helps me break my problems into smaller, more similar problems which can be recursed.  This allows for better code reuse and maintenance I think.

Wrapping It Up

I'd like to spend some more time with tail recursion as I think it's pretty important.  As well, I'll also talk about how you can do the same in C# as well (with a little work of course).  But in the mean time, I hope I've demonstrated the simple act of recursion, when to look for it, and how to exploit it.  Not all problems are ready for recursion, but when you find the right opportunities for them, it's quite powerful.

More Posts Next page »



What's New

CodeBetter.Com Blogs

James Kovacs
34 Posts | 106 Comments | 30 Trackbacks
Karl Seguin
122 Posts | 1,086 Comments | 291 Trackbacks
Glenn Block
43 Posts | 138 Comments | 81 Trackbacks
Matthew Podwysocki
30 Posts | 86 Comments | 74 Trackbacks
Peter's Gekko
536 Posts | 2,309 Comments | 578 Trackbacks
Ian Cooper [MVP]
31 Posts | 157 Comments | 122 Trackbacks
David Hayden [MVP C#]
281 Posts | 757 Comments | 570 Trackbacks
Jeremy D. Miller -- The Shade Tree Developer
544 Posts | 3,996 Comments | 1,783 Trackbacks
Aaron Jensen
10 Posts | 32 Comments | 18 Trackbacks
Kyle Baley - The Coding Hillbilly
83 Posts | 450 Comments | 143 Trackbacks
Greg Young [MVP]
92 Posts | 533 Comments | 240 Trackbacks
Patrick Smacchia [MVP C#]
55 Posts | 227 Comments | 263 Trackbacks
Dave Laribee
53 Posts | 345 Comments | 114 Trackbacks
Jeff Lynch [MVP]
226 Posts | 486 Comments | 99 Trackbacks
Jeffrey Palermo [MVP]
652 Posts | 2,475 Comments | 620 Trackbacks
Rod Paddock
37 Posts | 143 Comments | 40 Trackbacks
Jacob Lewallen
5 Posts | 40 Comments | 6 Trackbacks
Steve Hebert's Development Blog
309 Posts | 540 Comments | 95 Trackbacks
Raymond Lewallen
298 Posts | 1,917 Comments | 341 Trackbacks

Other Blogs

CodeBetter.Com Events
3 Posts | 0 Comments | 13 Trackbacks
CodeBetter.Com Link Blog
178 Posts | 9 Comments | 2 Trackbacks
All About Products
2 Posts | 4 Comments | 2 Trackbacks
Featured Articles
1 Posts | 4 Comments | 1 Trackbacks

CodeBetter.Com Alumni

Jean-Paul S. Boodhoo
136 Posts | 457 Comments | 132 Trackbacks
Don Demsak
5 Posts | 14 Comments | 1 Trackbacks
Jay Kimble -- The Dev Theologian
423 Posts | 1,431 Comments | 167 Trackbacks
Eric Wise
290 Posts | 1,480 Comments | 208 Trackbacks
Brian Peek [MVP C#]
15 Posts | 15 Comments | 3 Trackbacks
Mark DiGiovanni
88 Posts | 322 Comments | 38 Trackbacks
Paul Laudeman
113 Posts | 231 Comments | 22 Trackbacks
Ben Reichelt's Weblog
172 Posts | 514 Comments | 70 Trackbacks
Ranjan Sakalley
41 Posts | 272 Comments | 6 Trackbacks
Public Class GeoffAppleby
300 Posts | 1,943 Comments | 108 Trackbacks
DonXML - Live From PDC
3 Posts | 4 Comments | 3 Trackbacks
Grant Killian's Blog
171 Posts | 473 Comments | 8 Trackbacks

CodeBetter.Com Emeritus

Darrell Norton's Blog [MVP]
724 Posts | 2,380 Comments | 330 Trackbacks
Brendan Tompkins [MVP]
405 Posts | 2,715 Comments | 345 Trackbacks