Monday, April 14, 2008

seattle-skyline

This week I get to hang out with lots of smart people. Monday through Thursday is the Microsoft MVP Global Summit, and the ALT.NET Open Spaces, Seattle runs from Friday through Sunday.

One aspect of these events that I really like is the lack of name-dropping. It's just plain dangerous with so many "elites" walking about. I can imagine that the potential for an embarrassing faux pas is pretty high.

Fanboy Geek: "I was talking to Martin Fowler the other day and he said..."

Martin: "Hi, I'm Martin Fowler. Who the heck are you?"

posted on Monday, April 14, 2008 5:43:59 PM (Eastern Standard Time, UTC-05:00)  #    Comments [1]

kick it on DotNetKicks.com
 Wednesday, April 09, 2008

BlueMonster 

The rumors are all true. May 19, 2008 will be my first official day as an employee of Microsoft. Specifically, I will be joining the Visual Studio Team as a Program Manager.

This month marks five years since I joined the (then) fledgling CodeRush team at DevExpress as an outside contractor. (I later became a full employee in September of 2003.) The years seem to have passed quickly, yet we've accomplished an incredible amount with CodeRush and Refactor. It feels like just yesterday when Mark and I were doing our first proof of concept work for painting via managed code on the decidedly unmanaged Visual Studio editor. Yet today, we're shipping products with blazingly fast productivity boosts, more than 150 refactorings, and stunning next-generation UI. After five years, I still feel that CodeRush and Refactor are, hands down, the best Visual Studio productivity tools available.

I'm leaving quite a bit behind to join Microsoft. DevExpress is an amazing company to work for. If any readers are looking to work for a cutting-edge company at the top of its game, I recommend applying. At DevExpress, I've developed some strong friendships that are difficult to leave. Obviously, we'll keep in touch and see each other at conferences, but we won't be working together anymore. Ray, Julian, Kevin, Oliver, Courtney and Mehul will be greatly missed.

I'll especially miss working with the IDE Tools team (a few members of which are pictured below). Contrary to popular belief, Mark and I don't make up the entire IDE Tools team. In reality, it is staffed by some extraordinarily intelligent programmers—all of whom have been blessed with the ability to deal with Mark and myself.

IDE Team (partial)

One couldn't find a more talented group of people.

But scarecrow, I'll miss you most of all1.

garlic

Regardless of the garlic (viewable in the picture above) that you constantly hang over yourself to ward off vampires, the last five years have been the most enriching of my programming career. To say that "I've learned a lot" is a gross understatement. You truly are a visionary and an inspiring person to work for (with). From you, I've learned that presumed impossibility should never be a barrier to invention.

As much as I love DevExpress, it's time for a change. The company is in a really healthy place, and my leaving should cause minimal ripples. I think that I have a lot to offer in the IDE space at Microsoft, and it's a good time to move on.

In addition to leaving my current job, I will be moving to Seattle. For the next several months, my family and I will be going through the stresses of relocation. Is anyone interested in purchasing a charming two story, brick, four bedroom home in Toledo, Ohio?

1Hillary Flammond, Top Secret!

posted on Wednesday, April 09, 2008 11:19:47 AM (Eastern Standard Time, UTC-05:00)  #    Comments [16]

kick it on DotNetKicks.com
 Friday, April 04, 2008

Isn't She Hot? 

I have a terrible, secret shame: my writing skills are lousy.

For me, perhaps the most difficult aspect of blogging is the writing process. Sometimes I feel inspired, but more often, I struggle. No matter how profound my level of inspiration is, bugs always seem to work themselves into my writing. Missing words, grammar slip-ups, poor phrasing—you name it. I feel as if I've been cursed.

My frustration is probably due to my dislike of writing in school. Back then, it simply didn't interest me. I was too busy learning to code against the Zilog Z80, and playing Trade Wars on my local BBS. I suppose it didn't help that, for many years, the vast majority of my reading consisted of either technical books or comic books.

When I began blogging in August of 2006, my writing was... unpolished. I composed my posts with the same grace that elephants construct model airplanes. Sadly, I couldn't recognize my own weakness.

For awhile, my blog stayed pretty low on the radar. I wrote a few technical articles, but in February of 2007, I really hit my (first) stride writing articles about functional programming concepts using C# 2.0. I rolled into March, picking up steam until my writing and I reached an impasse.

On March 23, 2007, I posted an article that earned me a few negative emails. None of the emails criticized my content (which is still pretty cool). Instead, they (gently) pointed out typos, poorly-constructed sentences, and unclear tidbits.

Feeling frustrated and inept, I asked my trophy wife—who graduated with a minor in English Education—to take a look at my article. Graciously, she corrected my grammar, and I promptly re-posted it. So, everything was OK now, right? Wrong. The wind in my blogging sails had died down. My dear trophy wife continued to help me with blog posts, but my desire to blog had waned. Eventually, my output shrank to just a trickle.

Finally, on August 1, 2007, I was bit by the blogging bug for a second time. But this time was different. This time, I was playing it smart. I "employed" my trophy wife as a full-time editor. Since then, she has poured over every blog post with me.

My trophy wife is an especially good editor. In addition to navigating through my grammatical mine fields, she works hard to actually understand the concepts that I'm trying communicate. The process results in better-written articles that are more easily understood.

Since I got my second wind, blogging has been a joy. It's much more fun to have someone to bounce ideas off of ([ed.] Never end a sentence with a preposition, silly). But most importantly, it's provided a way to bring my trophy wife into my world.

posted on Friday, April 04, 2008 2:55:18 PM (Eastern Standard Time, UTC-05:00)  #    Comments [6]

kick it on DotNetKicks.com
 Thursday, April 03, 2008

 WeigtingApplesAndOranges

This recent blog post caused quite a stir on the F# mailing list. The post presents two solutions for Project Euler Problem 14: one in C# and the other in F#. The C# version clearly is hand-optimized for speed (and is indeed very fast), but the F# solution isn't. Instead, the F# code appears to be written with elegance and brevity in mind. Robert Pickering presented a challenge to create a faster F# solution, and the F# mailing list (which had been dormant for a couple of weeks) literally exploded with ideas.

Before we go too far afield, below are the instructions for Project Euler Problem 14.

The following iterative sequence is defined for the set of positive integers:

nn/2 (n is even)
n → 3n + 1 (n is odd)

Using the rule above and starting with 13, we generate the following sequence:

13 → 40 → 20 → 10 → 5 → 16 → 8 → 4 → 2 → 1

It can be seen that this sequence (starting at 13 and finishing at 1) contains 10 terms. Although it has not been proved yet (Collatz Problem), it is thought that all starting numbers finish at 1.

Which starting number, under one million, produces the longest chain?

NOTE: Once the chain starts the terms are allowed to go above one million.

As you can see, the problem boils down to generating one million sequences and counting the number of terms in each to find the longest. It's not rocket science, but there are many ways to optimize the solution. However, I'm not interested in creating the most optimal F# code to compete with the C# version. That's already been done by many of the gurus. Instead, I'd like to know if we can write C# code that more closely matches the algorithm used by the F# solution. Let's see how C# matches up when playing F#'s game.

Below is the F# solution that's caused so much debate.

#light

let seqLength n =
  n |> Seq.unfold
    (fun x -> match x with
             
| x when x = 0L      -> None
              | x when x = 1L      -> Some(1L, 0L)
              | x when x % 2L = 0L -> Some(x, x / 2L)
              | _                  -> Some(x, 3L*x + 1L))
    |> Seq.length

[for i in 1L..1000000L -> (i, seqLength i)]
  |> List.fold1_left(fun (ai,al) (i,l) -> if l > al then (i,l) else (ai,al))
  |> (fun (x,y) -> x ) |> print_any

If you've been following my F# articles, the code above shouldn't contain anything new. Pattern matching, tuples, option types, list comprehensions, functions and the forward pipe operator should all be reasonably familiar. The only item that truly requires explanation is the Seq.unfold function.

In F#, seq<'a> is an alias for the .NET interface, IEnumerable<T>, which is implemented by every collection in the Base Class Library and is the centerpiece of LINQ to Objects. In fact, in the F# libraries, seq<'a> is defined very simply as...

type seq<'a> = IEnumerable<'a>

See? Simple.

Seq.unfold is a library function that creates a seq<'a>, given a generator function. The resulting seq<'a> is lazily evaluated. That is, when a value in the seq<'a> is requested, the generator function is called to calculate it. In practice, it's similar to a C# iterator. The signature of Seq.unfold looks like so:

val unfold : generator: ('b -> ('a * 'b) option) -> 'b -> seq<'a>

The generator function is usually the part that trips people up. When called, the generator is passed a bit of state. This state is initialized by the second argument passed to Seq.unfold. To confuse matters further, the generator returns an option type containing a tuple. This option+tuple result represents three pieces of information:

  1. The option type indicates whether or not the sequence should continue. I.e., returning None signals the end of the sequence.
  2. The first part of the tuple is the current item in the sequence.
  3. The second part of the tuple is the bit of state that will be passed to the generator the next time it's called.

Note that the state and the result aren't required to be of the same type. This means that you can use Seq.unfold to generate some fairly flexible sequences. For example, we could produce the counting numbers as a sequence of strings.

1 |> Seq.unfold (fun i -> Some(i.ToString("#,#"), i + 1))

The above code produces an infinite sequence. That's OK because the sequence is lazy. However, we could introduce starting and stopping values by declaring a function and modifying the generator.

let count (start : int) stop =
  start |> Seq.unfold (fun i -> if i > stop then None
                                else Some(i.ToString("#,#"), i + 1))

That function can be called like so (using the F# Interactive Environment):

> count 1000 1003;;

val it : seq = seq ["1,000"; "1,001"; "1,002"; "1,003"]

Now that we have a better understanding of how Seq.unfold works, consider the generator function from the F# solution shown earlier.

(fun x -> match x with
          | x when x = 0L      -> None
          | x when x = 1L      -> Some(1L, 0L)
          | x when x % 2L = 0L -> Some(x, x / 2L)
          | _                  -> Some(x, 3L*x + 1L))

This very elegantly represents the rules of the sequence as defined by Project Euler.

nn/2 (n is even)
n → 3n + 1 (n is odd)

To create a C# solution that maps to the F# solution, we'll need to define an Unfold function. To do that, we need to create Options and Tuples. Below are the interfaces of the Option and Tuple types we'll use in C#.

public sealed class Option<T>
{
  public bool IsNone { get; }
  public bool IsSome { get; }
  public T Value { get; }

  public static Option<T> None { get; }
  public static Option<T> Some(T value) { }
}

public static class Option
{
  public static Option<T> Some<T>(T value) { }
}

public sealed class Tuple<T1, T2>
{
  public T1 Fst { get; }
  public T2 Snd { get; }
}

public static class Tuple
{
  public static Tuple<T1, T2> New<T1, T2>(T1 fst, T2 snd) { }
}

I don't want to derail our discussion by delving too deeply into them. If you're interested, you can download the source and explore them at your leisure. For our purposes, you can trust that they work as expected. One point of interest is the additional Option.Some<T>() and Tuple.New<T1, T2>() helper methods. These are in place to allow us to remove some code-clutter by taking advantage of the C# compiler's type inference for generic type parameters.

Defining Unfold as a C# iterator is fairly straightforward—that is, once you get past the scary nested generic type of the generator parameter.

public static IEnumerable<TResult> Unfold<T, TResult>(
  Func<T, Option<Tuple<TResult, T>>> generator, T start)
{
  var next = start;

  while (true)
  {
    var res = generator(next);
    if (res.IsNone)
      yield break;

    yield return res.Value.Fst;

    next = res.Value.Snd;
  }
}

Using Unfold, we can write C# code that determines the length of one of the Project Euler sequences, given a starting value.

public static long SeqLength(long start)
{
  return Unfold(x =>
    {
      if (x == 0L)
        return Option<Tuple<long, long>>.None;
      else if (x == 1L)
        return Option.Some(Tuple.New(1L, 0L));
      else if ((x % 2L) == 0L)
        return Option.Some(Tuple.New(x, x / 2L));
      else
        return Option.Some(Tuple.New(x, (3L * x) + 1L));
    }, start).Count();
}

That code is remarkably similar to the original F# code (restated below).

let seqLength n =
  n |> Seq.unfold
    (fun x -> match x with
             
| x when x = 0L      -> None
              | x when x = 1L      -> Some(1L, 0L)
              | x when x % 2L = 0L -> Some(x, x / 2L)
              | _                  -> Some(x, 3L*x + 1L))
    |> Seq.length

OK. The bulk of the work is complete. The rest of the solution can be coded with a query expression.

public static long GetLongestSequence()
{
  return (from i in Enumerable.Range(1, 1000000)
          select new { Start = i, Length = SeqLength(i) })
          .Aggregate((x, y) => y.Length > x.Length ? y : x)
          .Start;
}

Again, the symmetry between the C# query expression above and the original F# code below is striking.

[for i in 1L..1000000L -> (i, seqLength i)]
  |> List.fold1_left(fun (ai,al) (i,l) -> if l > al then (i,l) else (ai,al))
  |> (fun (x,y) -> x ) |> print_any

Where do we stand in terms of performance? Well, the C# code that we just wrote takes about 16 seconds to find the correct answer on my machine, but the F# solution comes in at around 12 seconds. The C# solution from the original blog post executes in about .047 seconds on my machine, but Robert Pickering's final F# solution takes .064 seconds. Is there a clear winner? In my opinion, no, not really.

So, what have we learned? When one takes the time to implement the same algorithm in each language, F# and C# really have a similar performance profile. However, the F# compiler definitely is tuned for elegance and beauty.

Instead of comparing apples to oranges, try comparing apples to apples and oranges to oranges. A performance comparison between two algorithms written in two different languages is interesting on some level, but it isn't really a fair comparison.

Download the source code for this article

posted on Thursday, April 03, 2008 7:40:31 AM (Eastern Standard Time, UTC-05:00)  #    Comments [3]

kick it on DotNetKicks.com
 Tuesday, April 01, 2008

Today is April Fool's Day—the day when many of us celebrate just how gullible we really are. Celebrants enjoy the day by spoofing co-workers and engaging in fun hoaxes and practical jokes.

Over the years, I've personally been the target of many an April Fool's prank. Considering today's date, I'm not sure what to make of the following email that I received this morning. Am I the target of yet another joke?

Congratulations! We are pleased to present you with the 2008 Microsoft® MVP Award! The MVP Award is our way to say thank you for promoting the spirit of community and improving people’s lives and the industry’s success every day. We appreciate your extraordinary efforts in Visual C# technical communities during the past year.

I suppose it's possible that Microsoft has a thoroughly sick sense of humor, and this is just an elaborate hoax. On the other hand, it could be that Microsoft has absolutely no sense of humor and doesn't realize that today isn't the most optimal day to be sending out congratulatory emails.

I feel that I have to give this email two responses:

  1. If this is real, I am completely humbled to be a recipient of the MVP Award this year. Blogging, speaking and educating are activities that I find very rewarding, and it's flattering to be recognized for them.
  2. If this is just an elaborate joke, I'm thoroughly disgusted and saddened by the juvenile attempt at humor. People have feelings, ya' know!

How hard is it to send these emails on March 31st or April 2nd? :-) That would clear up a lot of confusion.

P.S. I know it's real. Thanks Microsoft! I am truly honored. No joke.

posted on Tuesday, April 01, 2008 10:44:09 AM (Eastern Standard Time, UTC-05:00)  #    Comments [10]

kick it on DotNetKicks.com
 Thursday, March 27, 2008

Recently, I googled my first name. The search yielded some startling results. Not only was I surprised to find my modest blog on the front page, but... well... see for yourselves.

GoogleDustin

Sadly, soon after came the inevitable smack down.

GoogleDustin2

It's on. Now that I've had a taste of power, I'm willing to go to great lengths to quench my thirst. Look out Hoffman! I don't care if you are my namesake...

You're next Screech. No bell will save you this time.

posted on Thursday, March 27, 2008 7:15:52 PM (Eastern Standard Time, UTC-05:00)  #    Comments [1]

kick it on DotNetKicks.com
 Monday, March 24, 2008

Last month, I was scheduled to speak at the Findlay Area .NET Users Group (FANUG), but the meeting was canceled due to weather. This month, my good friends Jason Follas and Greg Huber were scheduled to speak, but a last-minute conflict has thrown a monkey wrench into the works. After passing a few emails back and forth, Jason and Greg have decided to reschedule. Instead, I'll be giving my Functional C# talk in Findlay tomorrow night. I hope to see you there!

Title: Functional C#

Abstract: In recent years, many features have been added to the C# language that make it possible to write programs using techniques from other programming paradigms. Chief among these is functional programming. Often regarded as only being academically useful, functional programming has many practical uses, some of which appear within the .NET Framework itself. In this session, we'll examine some ideas taken from functional programming and see how they might be implemented using language features that already exist within C#. In addition, we'll highlight ways in which the .NET Framework APIs borrow from functional programming.

posted on Monday, March 24, 2008 11:11:54 AM (Eastern Standard Time, UTC-05:00)  #    Comments [1]

kick it on DotNetKicks.com
 Thursday, March 20, 2008

GoogleAds

posted on Thursday, March 20, 2008 3:00:23 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]

kick it on DotNetKicks.com

A few days ago, my friend Michael Letterle (the artist formerly known as Michael.NET) twat the following tweet:

MichalL-20YearsToLate

The story Michael referred to is Landon Dyer's "Donkey Kong and Me" blog post, which chronicles his conversion of the Donkey Kong arcade game to the 8-bit Atari 400/800 systems. (Screenshots and a review of the port can be found here.) A fascinating yarn, Dyer's post evokes a feeling of nostalgia for the swashbuckling coder days of more than two decades ago. His recent post about the development of the Atari ST is equally enjoyable.

I've often shared Michael's sentiment. Sometimes, I feel like I was born a bit too late. At the advanced age of 0x20, I am fascinated by stories of the Herculean coding efforts of those who came before me—the original early adopters. (Although, there's a strong argument that the present day is just as, if not more, exciting.) Perhaps the most interesting aspect of tech history is how our forefathers were forced to invent creative solutions for just about everything. For me personally, that's what makes "Donkey Kong and Me" so much fun. The same appeal can be found in the early-Macintosh hardware-tweaking stories at Andy Hertzfeld's Folklore.org.

To fuel my interest in computer tech history, I've recently begun re-reading its bible: Programmers At Work.

ProgrammersAtWork2

Published in 1986, this book features interviews with an amazing array of programmers, including figures like Gary Kildall, Charles Simonyi, Jaron Lanier and even Bill Gates. It's out-of-print but can still be purchased used. (I "borrowed" my water-damaged copy from my father's bookshelf). Thankfully, Susan Lammers, the author, has recently started a "Programmers At Work" blog where she's posting the original interviews. So, if you can't find the book, these classic interviews should all be available soon.

What interesting tech history articles or books have you read recently?

posted on Thursday, March 20, 2008 12:39:47 PM (Eastern Standard Time, UTC-05:00)  #    Comments [0]

kick it on DotNetKicks.com