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]
 Saturday, April 21, 2007

Today is my friend Peter's birthday.  He and Jamie were up here last weekend, and we did a bunch of touristy things like go to the Space Needle.

As a result of them being here so recently, I have the most relevant birthday picture of him ever!

Anyway, I was so glad they could come out and hang with us.  If we're lucky, he'll get off his butt and update his blog with more than, "I made some food and it tasted good."

posted on Saturday, April 21, 2007 2:06:18 PM (Pacific Standard Time, UTC-08:00)  #    Comments [3]
 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 highest setting
    • Seattle - Most people I have observed cut it very low.  I started pretty low, and then raised it so I could get it through the tall spots without stalling the mower due to wet clumps of clippings bogging down the blade.  I think I need a sharpening, or a more powerful mower.

Right now, it kind of looks like a bad haircut. We'll see how it looks after the blades stand up again, and all the clippings die and turn brown.  It'll probably need another once-over soon to even things out. I was just happy that the mower fired up without difficulty after having been drained of it's vital fluids for the move.

posted on Monday, April 02, 2007 10:57:57 AM (Pacific Standard Time, UTC-08:00)  #    Comments [2]
 Thursday, March 22, 2007

For some reason, when I'm typing (and especially when I'm coding) I often conciously attempt to capitalize numbers under certain conditions.  For some reason, my brain thinks that there's a difference.  For instance, if I was typing HttpV4Implementation, I would probably end up with HttpV$Implementation because if there had been a letter there instead of a number, I would have capitalized it.  Does anyone else have this problem?  It's really frustrating because I often retype it several times making the same mistake each time before finally realizing what the problem is.

I think this may be caused by my handwriting style, which seems to be typical of engineers, where all letters are in captial form, but differ in size to indicate capitalization.  I've seen this referred to as "smallcaps".  Oddly enough, I didn't pick this up in college as an engineer.  I decided to start writing that way in junior high after noticing how cool my granddad's handwriting was.

posted on Thursday, March 22, 2007 10:13:48 AM (Pacific Standard Time, UTC-08:00)  #    Comments [0]