Friday, June 20, 2008

Some of my posts that I get the most recurring email/inquiries on are my various posts about the STDF (Standard Test Datalog Format) parser that I originally created as an experiment back in 2005.  After some help from a former collegue, I am pleased to announce that this is finally available on CodePlex as LinqToStdf!

It is a managed library for processing STDF files, and gives you a model to explore the data via Linq queries.  This means, you can leverage the wide variety of managed languages (C#, VB, F#, JScript, IronPython, IronRuby, Managed C++, Boo, etc.) to process the data in STDF files.  It also works in Silverlight!  It has built-in support for the V4 spec, but it's highly extensible and should be able to parse any version of the file format as well as custom records.  It can be configured to be highly strict and throw on format errors, or be robust in the face of issues that normal STDF processors would choke on to the point of being able to detect and repair corruption on the fly.

If that interests you, I'd love for you to drop by and take a deeper look at it and get involved in its ongoing development.  I've already got at least one person interested enough to contribute and ensure its success as a community project.  There is currently a "beta" release available, and hopefully we'll whip it into shape enough to call it v1.0 soon.

My hope is that this can be an adoption driver for .NET in the semiconductor industry and that through this project I can be an ambassador for the CLR in that area.

posted on Friday, June 20, 2008 1:05:13 PM (Pacific Standard Time, UTC-08:00)  #    Comments [0]
 Tuesday, June 10, 2008

I've been playing alot with beta 2 of Silverlight 2, and I've been totally amazed at the scenarios it enables.  Working hard down inside the CLR engine, we're sometimes insulated from some of the innovation going on higher in the stack and it blows us away when we do get a chance to see it.

One of the very cool things in Silverlight is "Deep Zoom", which came from the SeaDragon project from Microsoft Research.  I decided to try it out myself on a very large panorama that I made a long time ago in New Orleans.  Unfortunately, the current toolset seems to trip over the large file size (20516x15291).  I'm trying to find out the real story behind the limitation.  All I know right now is that smaller files work.

So, I decided to try to slice it up into smaller, manageable chunks and just butt them against one another to simulate one large file.  The problem was that I couldn't find a tool to do this that didn't also trip up over the size of the file.  So, I wrote my own.  There are likely better ways to do this, this was just a quick and dirty attempt to make something that didn't totally crawl to a halt due to page faulting (or outright throw OutOfMemoryException).

The code below is what I came up with.  I use System.Drawing.Bitmap, lock the portions of the image I need, and do the data copying myself.  I ended up with this solution because GDI+ (DrawImage) seems to like to make alot of buffers (big ones in this case), and I couldn't fall back on good ol' bitblt because I couldn't get the right kind of data structures without more copying of the data.  This runs plenty fast and only takes up marginally more memory than it takes to represent the original and the size of one of the destination tiles.

Unfortunately, The MultiScaleImage does some weirdness with image that are butted up against each other, and you get as much as a whole pixel of "space" between them, depending on your zoom level. I'm still looking into other possible workarounds. So, it's wasn't ultimately useful, but I thought the code was interesting enough, and probably has academic usefulness.  So, enough talk, here's the code:

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Drawing;
   4:  using System.Drawing.Imaging;
   5:  using System.IO;
   6:  using System.Linq;
   7:  using System.Runtime.InteropServices;
   8:   
   9:  namespace ImageSlicer {
  10:      static class Extensions {
  11:          public static IEnumerable<int> Times(this int number) {
  12:              for (var i = 0; i < number; i++) yield return i;
  13:          }
  14:      }
  15:   
  16:      class Program {
  17:          [DllImport("msvcrt.dll", SetLastError = false)]
  18:          static unsafe extern byte* memcpy(byte* dest, byte* src, int count);
  19:   
  20:          static void Main(string[] args) {
  21:              var sourcePath = args.FirstOrDefault();
  22:              if (String.IsNullOrEmpty(sourcePath)) {
  23:                  Console.WriteLine("No source image path provided");
  24:                  ShowUsage();
  25:                  return;
  26:              }
  27:              if (!File.Exists(sourcePath)) {
  28:                  Console.WriteLine("Source image path doesn't exist");
  29:                  return;
  30:              }
  31:              var gridSizeStr = args.Skip(1).FirstOrDefault();
  32:              int gridSize = 4;
  33:              if (gridSizeStr != null && !int.TryParse(gridSizeStr, out gridSize)) {
  34:                  Console.WriteLine("Could not convert {0} to a valid grid size",
  35:                      gridSizeStr);
  36:                  return;
  37:              }
  38:              if (gridSize < 2) {
  39:                  Console.WriteLine("The grid size must be greater than 1.");
  40:                  return;
  41:              }
  42:              try {
  43:                  Console.WriteLine("Slicing {0} into a {1}x{1} grid.",
  44:                      Path.GetFileName(sourcePath), gridSize);
  45:                  Console.WriteLine("Loading...");
  46:                  using (var sourceBitmap = new Bitmap(sourcePath)) {
  47:                      Console.WriteLine("Source Image: {0}x{1}",
  48:                          sourceBitmap.Width, sourceBitmap.Height);
  49:                      var sliceWidth = sourceBitmap.Width / gridSize;
  50:                      var sliceHeight = sourceBitmap.Height / gridSize;
  51:                      Console.WriteLine("Each slice: {0}x{1}", sliceWidth, sliceHeight);
  52:                      int tile = 0;
  53:                      foreach (var row in gridSize.Times()) {
  54:                          foreach (var column in gridSize.Times()) {
  55:                              Console.WriteLine("Creating {0} of {1} ({2},{3})",
  56:                                  ++tile, gridSize * gridSize, column, row);
  57:                              using (var destBitmap = new Bitmap(sliceWidth, sliceHeight)) {
  58:                                  var sourceData = sourceBitmap.LockBits(
  59:                                      new Rectangle(column * sliceWidth,
  60:                                          row * sliceHeight, sliceWidth,
  61:                                          sliceHeight),
  62:                                      ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
  63:                                  var destData = destBitmap.LockBits(
  64:                                      new Rectangle(0, 0, sliceWidth, sliceHeight),
  65:                                      ImageLockMode.WriteOnly, sourceData.PixelFormat);
  66:                                  unsafe {
  67:                                      byte* pSrc = (byte*)sourceData.Scan0.ToPointer();
  68:                                      byte* pDest = (byte*)destData.Scan0.ToPointer();
  69:                                      foreach (var line in sliceHeight.Times()) {
  70:                                          memcpy(pDest, pSrc, sliceWidth * 3);
  71:                                          pSrc += sourceData.Stride;
  72:                                          pDest += destData.Stride;
  73:                                      }
  74:                                  }
  75:                                  sourceBitmap.UnlockBits(sourceData);
  76:                                  destBitmap.UnlockBits(destData);
  77:                                  destBitmap.Save(String.Format("{0}_{1}_{2}.png",
  78:                                      Path.GetFileNameWithoutExtension(sourcePath),
  79:                                      column, row), ImageFormat.Png);
  80:                              }
  81:                          }
  82:                      }
  83:                  }
  84:              }
  85:              catch (Exception ex) {
  86:                  Console.WriteLine("Error processing image.");
  87:                  Console.WriteLine(ex.ToString());
  88:              }
  89:          }
  90:   
  91:          private static void ShowUsage() {
  92:              Console.WriteLine("Usage:");
  93:              Console.WriteLine("ImageSlicer.exe sourceImage [gridSize]");
  94:          }
  95:      }
  96:  }
posted on Tuesday, June 10, 2008 10:01:35 PM (Pacific Standard Time, UTC-08:00)  #    Comments [3]
 Wednesday, April 23, 2008

I've been doing some app-building with Silverlight lately and exploring the limitations of the platform in comparison to the full desktop CLR and what that means for the Silverlight "ecosystem".  Those limitations can be summed up with 3 items:

  1. Strict sandbox security model
  2. Reduced managed framework surface area
  3. No binary compatibility with libraries targeting the desktop CLR (eliminates the number of 3rd party components you can leverage).

I think #3 will begin to become a non-issue as more component providers provide builds for Silverlight. #2 can be broken down into 2 areas:

  • Full technology areas that are unavailable on Silverlight (LinqToSql, WinForms, etc)
  • Reduced/pruned APIs

The second is where my interest lies, and intersects with #1 (the new security model).  We've done extensive threat modeling against our APIs as well as automated tooling that has either removed (or made internal) certain APIs, or marked them as SecurityCritical, meaning they cannot be called directly from "user" code.

In addition, the security model requires safe, verifiable user code.  Normally when developing on the desktop CLR, unless you are specifically targeting a low trust environment, you can do whatever you like.

So, for this exercise, I pulled out my trusty STDF parser (blogged here and here).  I've used this project as a test vehicle for both v2.0 and Orcas, and it's served well as a project that leverages a large cross-section of features in the Framework, from high-level stuff like Linq down to expression tree inspection and further down to LCG/RefEmit.

In short, I was able to get the parser working without too much trouble. I felt like creating a source bed that intended to target both Silverlight and the Desktop should be an attainable goal.  You just have to switch your mindset from binary compatibility to source compatibility.

I combated the reduced surface area with extension methods, which worked quite well to centralize the "overload shims" that needed to be "Silverlight-only", as well as for a general refactoring tool.  My goal is to have all the desktop vs. Silverlight differences centralized into files that are either included or excluded from the build depending on which platform I'm targeting.  I wish you could create extension properties.  That would let me close all the surface area discrepancies that aren't caused by missing/irrelevant technology areas.

I was pleased that 99% of my LCG codegen stuff "just worked".  I make heavy use of Reflection.Emit via DynamicMethod to generate my record parsers based on attributes on the record classes.  The 2 problems I ran into were:

  • Visibility restrictions - The new security model won't let my dynamic methods see internals.  I had used this ability to keep the API clean.  I'm still figuring out the best approach, but it was simple enough just to expose those methods.
  • Verifiability - I had a few places where I was generating unverifiable code.  Some of these were my own codegen bugs, but others were just bad assumptions on my part.

This brings me to constrained callvirt, an interesting little IL tidbit I discovered in the porting process.  Calling conventions are subtly different between reference types and value types, and it also depends on whether the given method is actually overridden in the value type (which can lead to confusing breaks when that state changes).  In the v1.x days, you always knew the type you were dealing with, so it didn't matter that much and you could generally always create the right sequence of IL to make a call.  V2.0 introduced generics, which meant that you couldn't emit unified IL for both the possibility of reference types or value types.  This meant there needed to be a way to unify the IL for the 2 cases.  This is where the constrained prefix came in.  It allows you to write unified IL that works regardless of whether you're working with a value type or a reference type (think generics constrained by an interface, or calling a method defined on System.Object like ToString()).

Anyway, I was able to fix my unverifiable code by utilizing the constrained prefix.  It also simplified my codegen logic significantly in a number of places where I had different paths based on whether I was working with a value type or not.

All in all, I was pleased with the results.  I'll be posting a sample Silverlight app using the library when I get some UI stuff figured out.

posted on Wednesday, April 23, 2008 12:43:46 PM (Pacific Standard Time, UTC-08:00)  #    Comments [0]
 Monday, April 21, 2008

I've been horrible with blogging lately.  But, I would be remiss if I  neglected to mention Peter's birthday today.  Happy Birthday, Peter.

Hopefully the thing that's been clogging my blogging pipes will be gone soon.

posted on Monday, April 21, 2008 3:28:22 PM (Pacific Standard Time, UTC-08:00)  #    Comments [1]
 Monday, February 25, 2008

Some of my posts are really reactions to search queries that have previously landed on my blog.  If they did a search that got to my blog, but I know they didn't find what they were looking for, chances are they (or someone else) will do the same again.  And, if I HAVE the information they are looking for, it makes sense to just add the information, even if it's what I would consider well-known or common sense information. (common sense for software developers, that is)

One general search query I see again and again is something like "What is Action<T> for?" or "What is Func<T>?"

These are framework-provided, generic delegate types.  If you'll recall, delegates can be thought of as type-safe function pointers.  A delegate type really just captures a signature as "callable" object.  Leveraging generics to define delegate types that can capture common signatures is goodness, since they are very flexible and can be used by anyone.  This also aids in interop between different components, since a general signature is far more interopable than custom delegate types.

In v2.0, several functional-looking APIs were added that took delegates as arguments (think List<T>), so instead of adding a special delegate type for each API, several "generic" delegates were added to capture the "essence" of a signature such as Action<T> which takes T and does some action (returning void), Predicate<T> which takes T and returns bool (presumably doing some test against T), Comparer<T> which compares 2 T's, etc.

In v3.5, even more generalized functional patterns were introduced (used heavily in Linq).  And we added a bunch more Action<> "overloads" for functions returning void, and added Func<> "overloads" for functions with a return value.  (I use overload loosely since these are classes and not methods) These patterns dropped the semantic "meaning" of the delegate, and just went straight to the idea of capturing a signature.

These framework-provided delegates are useful for using in your own code rather than creating your own.  Whether you leverage the Linq-centric, super-generic Action/Func pattern, or opt to consume the more meaningful v2.0 Predicate, Comparer, etc. is up to you.

posted on Monday, February 25, 2008 11:12:15 AM (Pacific Standard Time, UTC-08:00)  #    Comments [0]
 Wednesday, January 09, 2008

A twist on Bill Cosby's humerous show,  the other day I said the following to my daughter:

I'm sorry, donkeys don't stick to the refrigerator.

Taken out of context, Becky thought it was pretty funny. Here's the context: I was playing with Jenna in the kitchen the other day, and she was playing with 2 plastic donkeys as well as some refrigerator magnets.  After seeing how the magnets stuck to the refrigerator, she tried to do the same with the plastic donkeys, which didn't work of course.

posted on Wednesday, January 09, 2008 10:40:08 AM (Pacific Standard Time, UTC-08:00)  #    Comments [2]
 Tuesday, December 11, 2007

markandjasonWell, my old-school buddy Jason turns 32 today.  Jason and I have been friends since pre-school.  We pretty much attended every year of school together, all the way through our undergraduate years.  Here's a picture of me and him (Jason on the left... I don't know what the heck I'm doing) at one of my brother's birthday parties.  He was the friend I got to invite.

Happy birthday, man.  Go play some slaughterball today for me.

posted on Tuesday, December 11, 2007 4:22:30 PM (Pacific Standard Time, UTC-08:00)  #    Comments [4]
 Sunday, December 02, 2007

CRW_6366It's Jenna's 2nd birthday!  Wow, I can't believe it's already been 2 years.  Here's one of the pictures we took yesterday for our Christmas cards.

That was really fun.  I don't have a nice flash, so I had to resort to auxiliary lighting.  All things considered, I think they turned out pretty well.

Jenna constantly amazes me with what she knows.  She was playing with some blocks this morning and I asked her how many blocks she had.  She said, "Let's count.  One... Two... Three... Four."  Wow.

She's counted as high as 20, and can say the entire alphabet.  She loves to play with toy animals and make them talk with each other.  She loves to play "knock knock", where she'll close a door, we'll knock and she'll let us in, grab our hand and pull us in for a "visit".  Fun times.

CRW_3639

posted on Sunday, December 02, 2007 3:47:37 PM (Pacific Standard Time, UTC-08:00)  #    Comments [0]
 Monday, November 19, 2007

This release was exciting me before I made the move to Microsoft, and getting to be a part of it has made me even more excited about what we're giving our customers in this release.  If you're not familiar with Visual Studio, it is a suite of software development tools for creating just about any application or library you can think of.  I'll be writing more about this release in the coming weeks, but for now, go to www.microsoft.com/vstudio and check it out!

posted on Monday, November 19, 2007 9:29:03 AM (Pacific Standard Time, UTC-08:00)  #    Comments [1]
 Wednesday, October 31, 2007

Vista's search rocks, but sometimes you're not interested in searching through the gigabytes of file contents, you just want to search on filename.  Good ol "dir /s".  But, you don't need to give up the indexed goodness for this.  Just use some of the special search syntax: "name:[string you're searching for]" in the search box.

posted on Wednesday, October 31, 2007 3:03:16 PM (Pacific Standard Time, UTC-08:00)  #    Comments [0]
 Monday, October 15, 2007

I certainly don't want this to turn into a video blog of fish, but I got some more video of the fish in our stream, and it's so unbelievable to me as someone new to this area that I simply must post it.  I've also done some tweaks to my custom Silverlight player as well as used some different encoding techniques (I haven't decided whether I like them yet).

Again, enjoy me sounding like an idiot.

[UPDATE:] The way I have embedded the player this time seems to prevent it from showing in most RSS aggregators. click through to my blog to see the video.

posted on Monday, October 15, 2007 2:02:31 PM (Pacific Standard Time, UTC-08:00)  #    Comments [0]
 Saturday, September 22, 2007

So, the salmon are running in our stream.  They're really big.  I caught this video today of a smaller female (I think).  Hopefully I'll get some bigger ones on video soon.  This is also an experiment with Silverlight.

Oh, by the way.  I'm like giddy with the thought of salmon in my stream, so I sound like an idiot.

posted on Saturday, September 22, 2007 6:57:50 PM (Pacific Standard Time, UTC-08:00)  #    Comments [2]
 Wednesday, August 29, 2007

I wish I had time to come up with more concrete information (examples/code) in this post, but I don't have the time to work that stuff up.  I did think it would be useful for people searching for solutions to this problem, so here it is in all its ambiguity.

I was playing with expression tree inspection and dynamic interpretation the other day, when I hit something that I was sure was a bug.  I was inspecting an expression tree, identifying "branches" of interest, and generating lamdba expressions from them on the fly.

You might do this to break up an expression into separate units of execution to spread across multiple processors (a la PLINQ), or to replace parts of a tree requiring local execution before passing off to another layer to be transformed into another domain like SQL, or whatever.  In any case, I was doing it.

I found that if the type of the expression was a value type, I could not create a lambda expression returning object from it, even though there is an inheritance relationship.  You get a fairly straightforward, but perhaps surprising exception.

After some back and forth with the Linq team, I discovered that this was by design.  In the case of value types, the boxing operation required to make an object must be represented by a unary convert expression. The solution is to wrap such expression trees with a call to Expression.Convert(expression, typeof(object)).

posted on Wednesday, August 29, 2007 4:17:11 PM (Pacific Standard Time, UTC-08:00)  #    Comments [0]
 Tuesday, August 28, 2007

Today is my 1-year anniversary at Microsoft.  I've been having a blast working on all kinds of crazy stuff including but not limited to:

And, Seattle has turned out to be a really fun place to live.

posted on Tuesday, August 28, 2007 9:34:52 AM (Pacific Standard Time, UTC-08:00)  #    Comments [2]
 Friday, August 03, 2007

Today is my buddy Dave's birthday.  Here's a picture of him from a few weeks ago when he visited, which was a blast.  I've really missed Dave since we moved to Washington, so it was awesome that he could visit.

Luckily, Halo 3 is coming out soon, so we'll be hanging out alot more virtually.

Happy Birthday, Dave!

posted on Friday, August 03, 2007 8:47:20 AM (Pacific Standard Time, UTC-08:00)  #    Comments [1]
 Thursday, July 26, 2007

An interesting pattern I've seen emerge since the early releases of Orcas is what I might refer to as "delegate properties".  What I mean by that is a property (or field, I suppose) that returns a delegate.  This pattern has some interesting implications.

First, in a language that treats delegates as directly callable objects, this pattern looks just like a method (someInstance.TheProperty(args)).  You can't tell the difference (although VS gives you different intellisense) by looking at a callsite like this. Among other things, this leads to some interesting naming issues.  Do you name it like you would a method?

Second, it opens up opportunities to do some really powerful (and slightly insane) hybrid inheritance models.  Think about a virtual delegate property that has both a getter and a setter, now think about trying to predict what that delegate will do when you call it.  It doesn't sound like something to recommend as part of a public API, but I think there are some interesting scenarios there.

If I come up with something interesting and useful, I'll let you know.

posted on Thursday, July 26, 2007 12:56:27 PM (Pacific Standard Time, UTC-08:00)  #    Comments [0]
 Tuesday, July 24, 2007

Today is our 8 year anniversary.  Eight years seems like a really long time!  This past year has been a crazy year for us.  We've moved across the country, away from all our friends and family.  And, through it all, Becky's put up with all my crazy shenanigans.

Thanks, Becky.

posted on Tuesday, July 24, 2007 3:44:48 PM (Pacific Standard Time, UTC-08:00)  #    Comments [1]
 Friday, July 20, 2007

Peter Three of my good friends came to visit in the past couple of weeks.  My friend Peter, who I met in the 5th grade (if I recall correctly) visited again last week.  Due to a bizarre coincidence, his wife had a one-week job in Bellevue, which is here on the east side of Seattle.  So, I got to hang out with him, which was a blast.

This week, my buddy Dave was here.  Dave and I played trombone together in college.  His visit was also somewhat coincidental, but I won't go into the details here.  He stayed with us and we hung out and we had all manner of good times.

Dave and Jeff While Dave was here, Jeff (one other trombone friends from college) came down from Bellingham to hang out for an evening, which was super-fun.  In another bizarre coincidence, his wife Bethany went to high school with Dave, so there was some reminiscing there as well.  Bethany's mom came along for the ride as well, and schooled us all in a game of Wii Sports bowling.

I was really bummed that these visits occurred right after our big vacation, which meant that I really couldn't afford to take a couple of days off to enjoy them.  So, sorry again for that guys.

posted on Friday, July 20, 2007 8:04:34 AM (Pacific Standard Time, UTC-08:00)  #    Comments [0]
 Wednesday, July 18, 2007

We got back from our big summer vacation a few weeks ago, and I've finally got all my photos processed and uploaded.  Here's the collection that combines the Cape Cod and Texas parts of the trip:

We had a really great time, aside from the ridiculous hassles of air travel.  Jenna got to meet her 2 cousins, and WE got to actually spend time with my brother and his family, which was something that was limited due to the sickness we had during our Christmas visit.

posted on Wednesday, July 18, 2007 8:52:19 AM (Pacific Standard Time, UTC-08:00)  #    Comments [0]
 Monday, July 16, 2007

If you have been following my series on delegates, you may have experimented with open-instance delegates and perhaps found it difficult to create an open-instance delegate for a value type.

If you'll recall, an open-instance delegate has an extra first parameter, used to pass the instance used for the invocation.  What's not made explicitly clear is that this first parameter must be passed by reference.

For reference types, you've automatically got a reference, but for value types, this must be a "ref" parameter.  For instance, a delegate type used as an open-instance delegate for Int32.CompareTo would have to be defined something like:

delegate int IntCompareToDelegate(ref int instance, int other);

Otherwise, you'll get a System.ArgumentException when you try to bind the method to the delegate, giving you the ever-helpful error message: "Error binding to target method".

There are lots of underlying reasons for this, both from a calling convention perspective, as well as a side-effect perspective.  But, you can simplify it by thinking about modifications to the instance.  If you passed by value (creating a copy that the method acted on), any changes made to the instance by the method would be lost because they happened to a copy.

In most cases, value types are immutable in the framework, but you could run into issues with your own types.  And, again, this isn't the only reason for this restriction (take a look at the IL generated for a value-type method call to get some more ideas).  It's just the easiest to understand.

If you'll recall, Orcas extension methods, which are similar in concept to this, do not follow this pattern and are subject to the infamous value type copying problems.

posted on Monday, July 16, 2007 11:24:58 AM (Pacific Standard Time, UTC-08:00)  #    Comments [0]
 Friday, June 22, 2007

 

I know, 2 picture-only posts in a row.  I couldn't resist this one though.

posted on Friday, June 22, 2007 8:34:46 AM (Pacific Standard Time, UTC-08:00)  #    Comments [2]
 Wednesday, June 20, 2007

posted on Wednesday, June 20, 2007 9:01:09 AM (Pacific Standard Time, UTC-08:00)  #    Comments [0]
 Wednesday, June 13, 2007

I was helping a friend with a problem recently.  He was taking a set of serial web service calls and doing them in parallel to save time, and was not up-to-speed on the best approach for that.  Once he settled on an approach, he realized that since his web service calls were being wrapped in an abstraction layer, he didn't have the Begin/End asynchronous call methods that are provided by the proxy class.

"No problem, just wrap them in a delegate".  The compiler automatically gives you Begin/EndInvoke methods in addition to the synchronous Invoke method.  And, you're guaranteed not to mess up the implementation because it's all provided by the CLR!  Just one of those things you might forget if you find yourself in the same situation.

posted on Wednesday, June 13, 2007 3:37:55 PM (Pacific Standard Time, UTC-08:00)  #    Comments [2]
 Thursday, May 17, 2007

After my last few CLR posts, I've had a couple of private inquiries regarding the usefulness of closed static delegates.  To bring everyone up to speed, a delegate pointing to an instance method needs a "target" instance to operate on (we'll get to open instance delegates later).  A static method, needs no such target, so we can leverage the "space" used for the instance case to carry around another object of interest.  We call a delegate with a provided value for this space "closed over the first argument".

For example, let's say we have a static method that does some operation on two numbers.  For simplicity, let's just say it adds them.  Our silly class and method might look like this:

public static class NumberFunctions {
   public static double Add(double first, double second) {
      return first + second;
   }
}

Normally, a delegate for this method would look like:

public delegate double BinaryOperation(double first, double second);

But, we're going to create a closed static delegate, which means we're going to "burn" the first argument into the delegate itself, so it's not needed in the delegate signature.  Instead, we'll use the following delegate signature (I didn't spend much time thinking up these names, I hope they make sense:

public delegate double ClosedCall(double other);

So, how do we create the delegate?  Normally, since C# (pre-Orcas) doesn't have syntax for creating closed static delegates, you are forced to use one of the Delegate.CreateDelegate overloads:

ClosedCall addToOne = (ClosedCall)Delegate.CreateDelegate(
        typeof(ClosedCall),
        1.0,
        typeof(NumberFunctions).GetMethod("Add", BindingFlags.Public | BindingFlags.Static));

Of course, we just spent 2 entries looking at a helper that can do this for us (I'm not claiming this is better, I just want you to be able to see what's happening):

ClosedCall addToOne = DelegateBinder.Bind<ClosedCall>(1.0,
        typeof(NumberFunctions).GetMethod("Add", BindingFlags.Public | BindingFlags.Static));

Now, a call to addToOne(someNumber) will yield the result of adding the supplied argument to one.  This is a contrived example, but you could imagine taking a method (perhaps generated on the fly via LCG), and "attaching" an instance to it via the first argument.  Then, being able to call it many times with different subsequent arguments, or passing it to another component that would provide the rest of the arguments.  In this way, you get the benefits of not having to keep track of an instance, without having to own the API for the instance.  Additionally, you could "chain" delegates together so that many arguments are captured in a stack of delegate calls, allowing closure-type semantics at the cost of some stack space (although since C# has closure support, you'd never really need to do that).

What's really cool is that with C# 3.0's Extension Methods feature, we now have language support for creating early-bound closed-static delegates.  If you bind a delegate to an extension method (using the regular syntax for an instance method), you will get the exact IL for creating an early-bound closed static method without our fancy helper class.  Let's see how that would look.  Let's use a different example to keep us on our toes.  Here's a helper function that creates email addresses:

public static class StringExtensions {
   public static string MakeEmailAddressWithAlias(this string domain, string alias) {
      return string.Format("{0}@{1}", alias, domain);
   }
}

Notice the "this" in front of the first parameter, this tells the compiler that the method should be considered when resolving method calls for string.  We'll use one of the delegate types provided in Orcas. Now, here's how the bind looks:

string fooDotCom = "foo.com";
Func<string, string> makeFooDotComAddress = fooDotCom.MakeEmailAddressWithAlias;

string email = makeFooDotComAddress("bar");

So, the result is that email will be bar@foo.com.

Hopefully, through these contrived examples, you can see the scenarios that closed static methods provide, as well as learn how you can create one the easy way with extension methods in Orcas.

posted on Thursday, May 17, 2007 9:46:22 AM (Pacific Standard Time, UTC-08:00)  #    Comments [0]
 Monday, May 14, 2007

In my last post, I showed a nifty way of constructing "early-bound" delegates using LCG.  Here's the same helper class implemented without LCG:

public static class DelegateBinder {
	public static TDelegate Bind<TDelegate>(object firstArg, MethodInfo method) {
		return (TDelegate)Activator.CreateInstance(
			typeof(TDelegate),
			firstArg,
			method.MethodHandle.GetFunctionPointer());
	}
} 

This one is quite a bit simpler, and extrapolating from what we learned last time, it's easy to see what's happening.  Hopefully, you are already familiar with the Activator class.  Basically, this just shows the managed call chain that produces a function pointer to a method given a MethodInfo.

I really like the LCG-based implementation, but only because of my love of DynamicMethod.  It's pretty complex, and aside from opportunities for caching, doesn't really have anything over this implementation. This one is just plain simple, and would have a single-line implementation if I hadn't put some line breaks to avoid formatting problems.  It does, however, highlight the annoyingness of having to work around the compilers' "helpfulness" when it comes to delegate construction.  If only I could just call the constructor directly.

It is worth noting that this doesn't work in the Silverlight 1.1 alpha or the compact framework (or XNA for that matter), neither of which expose RuntimeMethodHandle.GetFunctionPointer().

posted on Monday, May 14, 2007 3:40:01 PM (Pacific Standard Time, UTC-08:00)  #    Comments [2]
 Friday, May 11, 2007

In a previous post about delegates, I discussed the following interesting cases of delegates:

  • Closed static
  • Open instance

See the previous post for the full explanation, but these basically open up some interesting dynamic scenarios.  The problem is that C# and VB do not expose syntax for constructing these in an "early-bound" fashion, that is using the special constructor on the delegate type rather than Delegate.CreateDelegate (which more or less binds via reflection).

For most scenarios this is not a huge problem, but there are some performance considerations and other issues to consider that I don't really want to dig into at the moment.  One sufficiently important scenario is testing early-bound invocation.  If your language doesn't support something, how can you test it?  Well, you can write the whole test in IL, but that is not a terribly maintainable proposition.

Another option is to only write the part you need in IL.  Unfortunately, C# doesn't allow you to write inline IL, but you can use Reflection.Emit.  And, since v2.0, you can use LCG (Lightweight Code Generation) via DynamicMethod.

The trick here is to understand how delegates are instantiated.  Delegates are just classes like any other.  They inherit from MulticastDelegate (typically).  The special part is that the runtime provides all the implementation and they have a special constructor.  Here's (approximately) the constructor signature for System.Action<T>:

public Action(object o, IntPtr method)

Object? IntPtr?  What the heck? Well, it's not as bizarre as you might think.  The object is simply the first argument for the invocation.  This allows binding to a particular instance ("this" for instance methods, arg 0 for static methods). The IntPtr is a pointer to the method.  "Pointers?!!?!?! in managed code?!?!" you say?  That's right, a pointer.  An object is easy enough to come by, but where do I get the pointer?  Well, the pointer can be easily retrieved via the ldftn opcode.  It loads the address of a given method (described via a token in IL, and a MethodInfo in Reflection.Emit).

Lets cut to the chase.  Here's a little class that can bind a method to a delegate type and allow you to provide the first argument (you'll need System, System.Reflection, System.Reflection.Emit using statements):

public static class DelegateBinder {

    public delegate TDelegate Binder<TDelegate>(object firstArg);

    public static TDelegate Bind<TDelegate>(object firstArg, MethodInfo method) {
        DynamicMethod dynMethod = new DynamicMethod("PassthroughBinderImplementation", typeof(TDelegate), new Type[] { typeof(object) }, typeof(DelegateBinder));
        ILGenerator gen = dynMethod.GetILGenerator();
        //load the first argument
        gen.Emit(OpCodes.Ldarg_0);
        //load the address of the method
        gen.Emit(OpCodes.Ldftn, method);
        //create the delegate
        gen.Emit(OpCodes.Newobj, typeof(TDelegate).GetConstructor(new Type[] { typeof(object), typeof(IntPtr) }));
        gen.Emit(OpCodes.Ret);
        return ((Binder<TDelegate>)dynMethod.CreateDelegate(typeof(Binder<TDelegate>)))(firstArg);
    }
}

With this class, you can dynamically construct all the early-bound variants (ignoring variants for signature relaxation) like so:

using System;
using System.Reflection;
using System.Reflection.Emit;

public delegate string Passthrough(string str);
public delegate string BoundPassthrough();
public delegate string ProgramPassthrough(Program p);

public class Program {
    static void Main(string[] args) {
        Console.WriteLine("Open Static:");
        Passthrough ospt = DelegateBinder.Bind<Passthrough>(null, typeof(Program).GetMethod("StaticImplementation", new Type[] { typeof(string) }));
        Console.WriteLine(ospt("Hello World"));

        Console.WriteLine("Closed static:");
        BoundPassthrough cspt = DelegateBinder.Bind<BoundPassthrough>("Hello World", typeof(Program).GetMethod("StaticImplementation", new Type[] { typeof(string) }));
        Console.WriteLine(cspt());

        Console.WriteLine("Open Instance:");
        ProgramPassthrough oipt = DelegateBinder.Bind<ProgramPassthrough>(null, typeof(Program).GetMethod("InstanceImplementation", Type.EmptyTypes));
        Console.WriteLine(oipt(new Program("Hello World")));

        Console.WriteLine("Closed Instance:");
        BoundPassthrough cipt = DelegateBinder.Bind<BoundPassthrough>(new Program("Hello World"), typeof(Program).GetMethod("InstanceImplementation", Type.EmptyTypes));
        Console.WriteLine(cipt());
    }

    public static string StaticImplementation(string str) {
        return str;
    }

    public Program(string payload) {
        _Payload = payload;
    }

    string _Payload;

    public string InstanceImplementation() {
        return _Payload;
    }
}

So, there are certainly cases that will break this, most involving incompatible signature issues between the method, delegate, and the first argument.  But I didn't want to make things more complicated for an example. Besides, the point of this is not really to give you some neat tool (you'll probably never need to do this), but to give people a better idea what the compiler is doing for you when you create a delegate.

posted on Friday, May 11, 2007 2:54:23 PM (Pacific Standard Time, UTC-08:00)  #    Comments [1]
 Thursday, May 10, 2007

One of my most successful comedic performances has got to be my rip-off of Dana Carvey's Grumpy Old Man character from SNL.  It was fun to pretend to be old.

Last night, I really felt old.  I was overseeing the youth as they played a variant of hide and seek, and I realized that there was something going on that I had never experienced.  The youth were using their cell phones to call each other and brag about their hiding places and trash-talking with the seekers about how they were never going to find them and such.  It was so interesting.  When I played hide and seek as a kid, not even our parents had cell phones!  Now everyone has them.  It was just a bizarre revelation.

posted on Thursday, May 10, 2007 8:59:57 AM (Pacific Standard Time, UTC-08:00)  #    Comments [7]
 Monday, April 30, 2007

Today is the MIX07 keynote (watch it live right now).  Scott Guthrie is currently on-stage spilling the beans about what's been going on here.  He just announced that Silverlight (v1.1) includes a cross-platform (Mac/PC at the moment) version of the CLR and the .net framework. I'll be talking about this alot in the coming months.  It's incredibly exciting stuff.

The NetFlix guys are on-stage showing off a demo of their new over-the-web movie viewing experience.  I hadn't seen this demo before. Very cool.

Scott just did his chess demo where the CLR engine plays chess against the IE javascript engine.  Very funny.

Scott just demoed cross-platform debugging (Running a Silverlight program on the Mac and hitting a breakpoint inside VS running on a PC).  Fantastic.

Scott's doing his airline demo.  I love this one because he starts with a cheesy "Hello World" app, and ends up with a fully-functional airline flight schedule viewer with crazy animations of planes flying around.

Scott just announced open source Ruby for .NET (IronRuby).  He's developing a Silverlight app with Ruby on the Mac with standard Mac tools.  Good job, John.  Now he's showing the dynamic language console, that gives you an interactive REPL console with Intellisense that can use any of the dynamic languages, or even mix the languages together on the fly.  All in the browser.  Freaking awesome.  I think alot of people missed the announcement about the DLR (dynamic language runtime) that anyone can use to build a dynamic language on top of .Net.

Wow, I've seen the MLB demo, but I hadn't seen the version running on the mobile phone!

posted on Monday, April 30, 2007 9:07:59 AM (Pacific Standard Time, UTC-08:00)  #    Comments [2]
 Monday, April 23, 2007

In all the busy-ness of the last week or so, I neglected to announce that my brother-in-law Ben and his wife Nicole had their baby.  Congratulations to them.  We're looking forward to meeting Cormac Anthony Patterson in person this summer.

posted on Monday, April 23, 2007 10:52:33 AM (Pacific Standard Time, UTC-08:00)  #    Comments [2]
 Monday, April 02, 2007

This weekend, I mowed my lawn for the first time since we moved here.  It needed it pretty bad, but I have been putting it off.  I just need to get used to cutting the grass when it's wet.  Mowing in the northwest is quite a bit different than mowing in central Texas. You can boil the differences down into the following:

  • Temperature
    • Central Texas - Pretty much sweltering at any time you need to mow.
    • Seattle - I had a light jacket on.  I've never mowed when it was so cool out.
  • Moisture
    • Central Texas - You can usually wait until the lawn is dry to mow
    • Seattle - No such guarantee that your free time will line up with a time where the grass is dry
  • Grass Type
    • Central Texas - All the lawn I've ever mowed have had st. augustine grass.  Wide, stiff blades.
    • Seattle - Most grass around here is very fine, soft blades. (which makes for quite a mess when it's wet)  In addition, there is alot of moss in the grass, especially after the rainy season.
  • Natural Variable Obstacles - Things that can move that you have to worry about running over.
    • Central Texas - Fire ant mounds could get big enough to cause issues, as well as some pain if you weren't careful.
    • Seattle - Pinecones can be big enough to cause problems.  Mole hills are also a new threat, especially since they often contain rocks large enough to be problematic.
  • Cutting height
    • Central Texas - You pretty much want to keep the grass as tall as possible so that it can retain moisture and keep from dying in the sun.  I usually cut on the high