It has been a while since I have posted.  We have been working hard to get Orcas beta 1 and beta 2 done.  So I apologize for the long interlude between posts but I hope that you are enjoying beta 1 and that you are looking forward to beta 2.

Now that beta 1 is out there, what do you all think of it?  Beta 1 has most of the features that we intend to put into Orcas but not all of them.  Some notable differences you will see in later releases are improved performance, error messages, error recovery, stability, and a few refinements.  Basically the kind of polish that people expect as a product nears completion.

Partial Methods

One feature that you may have not heard of yet is a feature called partial methods.  This is some of the work that I did in the last coding milestone a few months back.  Partial methods are methods that enable lightweight event handling.  Here is an example declaration:

partial class C
{
  static partial void M(int i);
}

There are a few notable things here:

1.  Partial methods must be declared within partial classes

2.  Partial methods are indicated by the partial modifier

3.  Partial methods do not always have a body (well look at this more below)

4.  Partial methods must return void

5.  Partial methods can be static

6.  Partial methods can have arguments (including this, ref, and params modifiers)

7.  Partial methods must be private

Now suppose that I make a call to C.M.

partial class C
{

  static void Main()
  {
    C.M(Calculation());
  }
}

Since M has no body, all calls to C.M are removed at compile time as well as the evaluation of the arguments.  So the above program is equivalent to:

partial class C
{

  static void Main()
  {
  }
}

In this sense, partial methods are the distant cousins of conditional methods which also sometimes remove the call and the evaluation of the arguments.  But partial methods go even further.  When a partial method has no body then the partial method is not even emitted to metadata.

So far this might seem a little confusing.  C# now allows users to declare methods for which the calls, the evaluation of the arguments, and the method itself are not emitted.  Fortunately, the story doesn't end there.  Partial methods allow users to define a body for the method so that the method, the calls, and the evaluation of the arguments are emitted.

partial class C
{
  static partial void M(int i); // defining declaration
  static partial void M(int i)  // implementing declaration
  {
  }
}

In the code above, we see that there is a difference between a defining declaration of a partial method and an implementing declaration of a partial method and the difference is whether or not the method has a body.  These definitions don't have to be in the same partial class declaration.  There may only be one defining declaration and if a defining declaration exists then there may be an implementing declaration.

Why Partial Methods?

So how are these partial methods used?  The common scenario is to use them to do lightweight event handling.  For example a tool that generates code may wish to have hooks for users to customize what code is run.  For example, imagine that a tool generated a bunch of code for a class representing a customer.  It might look like this:

partial class Customer
{
  string name;

  public string Name
  {
    get
    {
      return name;
    }
    set
    {
      OnBeforeUpdateName();
      OnUpdateName();
      name = value;
      OnAfterUpdateName();
    }
  }

  partial void OnBeforeUpdateName();
  partial void OnAfterUpdateName();
  partial void OnUpdateName();
}

If the user doesn't add any implementing definitions then this code is equivalent to:

partial class Customer
{
  string name;

  public string Name
  {
    get
    {
      return name;
    }
    set
    {
      name = value;
    }
  }

}

No extra metadata for things that are not used and no extra instructions for useless operations.  On the other hand if the user listened to the OnUpdateName "event" like this:

partial class Customer
{
  partial void OnUpdateName()
  {
    DoSomething();
  }
}

Then the original definition is equivalent to:

partial class Customer
{
  string name;

  public string Name
  {
    get
    {
      return name;
    }
    set
    {
      OnUpdateName();
      name = value;
    }
  }

  partial void OnUpdateName();
}

Comparing Partial Methods to the Alternatives

At this point, it is sensible to ask why not just use subclassing and virtual methods?  Of course, this would also work but it does have the drawback that the calls, the methods, and the evaluation of the arguments will still be emitted even if the virtual methods are not overridden.  So in a system like Linq to SQL that has thousands of little events it allows these events to be very lightweight so that the user only pays for those events that she uses.

A Few Fine Points

Consider the following program...

partial class C
{
  static void Main()
  {
    int i = 3;
    C.M(i = 5);
    Console.WriteLine(i);
  }
}

What does it write to the console?  3, 5, ...?

Actually, it is impossible to tell from just this code.  If there is no implementing declaration then the program will display 3 because the i = 5 will never be evaluated, but if there is an implementing declaration then the program will display 5.  The same is true for conditional methods.  So if you want a side-effect to occur make sure you do not cause the side-effect to occur as an argument to a partial method.  Of course, the same trick can be used to hide expensive calculations.

partial class C
{
  static void Main()
  {
    C.M(VeryVeryExpensiveCalculation());
  }
}

If there is no implementing declaration then the very very expensive calculation will never be performed.

Now what about attributes, how does those work?

partial class D
{
  [W]
  [return:X]
  partial void M<[Y]T>([Z]int foo)
  {
  }

  [Z]
  [return:W]
  partial void M<[X]T>([Y]int foo);
}

What attributes are actually emitted on M?  W and Z are the attributes on M; X and W are the attributes on the return type; Y and X are the attributes on the type parameter; Z and Y are the attributes on the parameter.

Enjoy!