Friday, April 29, 2005

John Lam claims that C#'s "using" blocks aren't "extensible to let us do arbitrary things".  He shows us an example of doing arbitrary things in statement blocks in Ruby.  I'll agree that his example is slick, using a continuation to yield control to the block, but there's certainly nothing keeping you from getting same functionality in C#.  The "using" block is simply a mechanism that utilizes the Dispose pattern to do things when you're done with them.  I've done everything from the standard releasing of resources to implementing reader/writer locks with them.

To speak to John's example, there's nothing keeping you from creating a wrapper or subclass that calls SetInfo in the Dispose method to accomplish the same thing.  Or, you could create a generic factory pattern that uses delegates to define the creation and disposing actions: 

public delegate T Creator<T>();

public class DisposingFactory<T> : IDisposable {

    Creator<T> creator;

    Action<T> disposeAction;

    public DisposingFactory(Creator<T> creator, Action<T> disposeAction) {

        this.creator = creator;

        this.disposeAction = disposeAction;

    }

    bool valueCreated = false;

    private T value;

    public T Value {

        get {

            if (!valueCreated) {

                value = creator();

            }

            return value;

        }

    }

    public void Dispose() {

        if (valueCreated) {

            disposeAction(value);

        }

    }

}

This also incorporates thunk-like lazy creation.  I'll admit to not having alot of Ruby experience, but it seems to me that "using" is every bit as "extensible" as far as executing code at the end of a block.  Here's John's example using the above with some pseudo-code:

using (DisposingFactory<VirtualDirectory> factory = new DisposingFactory<VirtualDirectory>(

        delegate() { return VirtualDirectory.CreateFromMoniker("some url"); },

        delegate(VirtualDirectory value) { value.SetInfo(); })) {

    factory.Value.AccessRead = true;

    factory.Path = "c:\foo";

}

You could, of course, bake the delegates into a class to make it simpler.  I suppose the most appropriate rebuttal to John's claims would be a wrapper class that takes care of it in the same way his example does, but I thought this example was a little more interesting.

John, I'd love to hear your feedback on this.  I'm sure there's lots I could learn from you.

[Update] dasBlog swallowed my generics, so I had to fix them.

posted on Friday, April 29, 2005 8:12:05 AM (Pacific Standard Time, UTC-08:00)  #    Comments [4]
 Thursday, April 28, 2005

With Don Box doing all manner of crazyness with anonymous delegates recently, I decided to do some experimenting of my own. While doing so, I ran into an interesting problem.  I was toying with a robust action scheduling mechanism that serializes actions to disk to make sure that they won't be lost in the case where the host process is stopped for some reason.

I was using the generic Action delegate to represent the actions and using anonymous delegates to inject things like action rescheduling.  I was pleased to see that basic anonymous delegates were serialized without issue.  But, when I started to use the closure features of anonymous delegates, it stopped working.  I was dissapointed, especially when I figured out why.

When you create an anonymous delegate without using outer variables, it is hoisted into the enclosing class as a private method with a compiler-generated name (that appears to be generated based on a combination of the signature and some randomness).  For example:

[Serializable]
public class Example {
  void Test() {
    Action action = delegate(DateTime scheduledTime) {
      Console.WriteLine("blah");
    };
  }
}

This actually turns into something like:

[Serializable]
public
class Example {
  void Test() {
    Action action = new Action(CompilerGeneratedName);
  }

  void CompilerGeneratedName(DateTime dateTime) {
    Console.WriteLine("blah");
  }
}

Actually, it does some niftyness to cache the delegate, but that's not important for this example. As you can see, serialization isn't a problem here.  However, if you use an outer variable within the method, the compiler hoists both the method and the variable into a nested class so it's available later when the delegate actually runs.  For example:

[Serializable]
public
class Example {
  void Test() {
    string foo = "blah";
    Action action = delegate(DateTime scheduledTime) {
      Console.WriteLine(foo);
    };
  }
}

This turns into something like:

[Serializable]
public
class Example {
  void Test() {
    CompilerGeneratedClassName something = new CompilerGeneratedClassName();
    something.foo = "blah";
   
Action action = new Action(something.CompilerGeneratedName);
  }

  private class CompilerGeneratedClassName {

    public string foo;

    void CompilerGeneratedName(DateTime dateTime) {
      Console.WriteLine(foo);
    }
}

Pretty cool, eh? Yeah, so what's the problem?  Well, the nested class is not marked with SerializableAttribute, so it can't be serialized, which makes the delegate serialization fail.  This seems like a big problem to me.  There may be a legitimate reason for this, but I don't see it.  I think the compiler ought to decorate the nested class if the enclosing class is also decorated.

There may be a way around this, but I haven't found it yet.  Any suggestions?

[Update] If you think this is a problem too, then vote for it.

posted on Thursday, April 28, 2005 5:55:08 PM (Pacific Standard Time, UTC-08:00)  #    Comments [0]
 Monday, April 25, 2005

With Becky's family in town this weekend, I took her brother Ben to play some frisbee golf.  We met up with Dave at the Wells Branch course near our house.  The weather was really nice despite a nagging wind which made it a bit tough.  As usual, there were some great moments and some mishaps.  I brought the camera along and captured some choice moments like this one of Dave leaping across the stream after retrieving a stray disc.  The pictures turned out really well.  Check out my photoset!

posted on Monday, April 25, 2005 9:57:13 AM (Pacific Standard Time, UTC-08:00)  #    Comments [2]

This weekend, Becky had her masters recital.  She's been at UT for the last two years getting her masters in French Horn performance.  It was fabulous! She played what was, in my opinion, an incredibly hard program.  One piece was difficult enough that she went through about a dozen accompanists before one could commit to the piece, which was modern and weird, but exceptionally performed. Congratulations Becky!

Her parents and brothers were in town, as were my parents, brother and sister-in law.  It was a great time.  Jen and Dave were there as well.  Since there were 3 Flickr-ers there, I created a Flickr group to share all the photos.  Check it out.  There are some great shots from everyone. Our mothers brought a huge spread for the reception after the recital.  Thanks again for that you guys. After the reception, the gang came back to our place for some fajitas a la Mark and Dave, which seemed to be well received.

The weekend was exhausting overall and left me feeling sick Sunday morning.  But I'm feeling better now.  Bring on the new Halo maps!

posted on Monday, April 25, 2005 9:48:28 AM (Pacific Standard Time, UTC-08:00)  #    Comments [2]
 Thursday, April 21, 2005

DSC00021It's my friend Peter's birthday today.  I'd tell you how old he is, but I don't even remember how old I am.  Here's a picture from a couple of years back of Peter in the Olive Garden in Waco, Texas.  I believe the haircut is a few revisions behind, but the goofy grin is up to date.  Sometime, we'll make it out to Cali for a visit and stay at their new place.

Happy Birthday, buddy.  I believe I have the distinction of being the first to say it online.

posted on Thursday, April 21, 2005 9:33:52 AM (Pacific Standard Time, UTC-08:00)  #    Comments [1]
 Friday, April 15, 2005
I've helped several people (at least attempted to anyway) track down memory "leaks" due to undisposed objects in .NET.  I thought those people would find Rico's latest tidbits to be very useful.  He gives several techniques for tracking down where the problems are.  Good read. 
posted on Friday, April 15, 2005 12:32:03 PM (Pacific Standard Time, UTC-08:00)  #    Comments [0]
 Thursday, April 14, 2005

We're making the move to 64-bit at work, and one of the things that's annoying me the most is all the 32-bit shell extensions that I rely on and didn't realize it.  For example, we use Subversion for source control and use the excellent TortoiseSVN shell extension to work with it from explorer.  Since it's a 32-bit extension, it doesn't show up in the context menu.

There are two workarounds I've found for using these 32-bit extensions.

  1. Use the 32-bit explorer.exe in the SysWow64 directory.  You have to have the "Launch folder windows in a separate process" option turned on, otherwise it will just see that explorer is already running and start a new 64-bit window instead of a new 32-bit process.
  2. Use 32-bit IE.  There's already a shortcut to it by default in the start menu.  Just fire it up and navigate to the filesystem instead of a web page.  Voila! 32-bit extensions start showing up.  I like this method since I don't have to have a bunch of explorer processes for each window.

There's probably a cleaner way of using the 32-bit explorer, but I haven't figured it out yet.

posted on Thursday, April 14, 2005 10:42:18 AM (Pacific Standard Time, UTC-08:00)  #    Comments [0]
 Saturday, April 09, 2005

CRW_2817Becky's dad was in the Dallas/Fort Worth area for a conference, and "dropped by"  By dropping by, I mean he took a 6 hour round trip out of his way.  I suppose that's better than the 16 hour round trip it would be from El Paso.  We went to Pasado's for dinner Friday night and had a nice time catching up.  Thanks for stopping by!

posted on Saturday, April 09, 2005 6:17:22 PM (Pacific Standard Time, UTC-08:00)  #    Comments [0]

My dad came down today to help me with a bathroom remodelling project.  We were basically removing a wall in the bathroom, but it was a little more complicated.  The wall goes all the way to the roof, and takes a couple of corners.  Luckily, the upper portion was structurally sound enough to support itself without the lower wall. Click through the picture on the left to see the stuff we did.  You can also check out the bathroom remodelling photoset for some more context.

A big thanks to my mom and dad for coming down to help.  I'm sure he'll have his pictures up soon.

[Update] Dad's got his entry up with links to pictures.

 

posted on Saturday, April 09, 2005 6:11:43 PM (Pacific Standard Time, UTC-08:00)  #    Comments [1]
 Friday, April 08, 2005

Last night, I completed my STDF file parser that I started over the weekend.  I'm pretty happy with it.  I now fully support all of the version 4 spec.  It's written with the Feb. 2005 CTP of Whidbey.  It was primarily a good example of a "real world" application, so I wanted to use it to try out some of the spiffy new features and see how they might fit into an application that was not built for the sole purpose of showing them off.

I'm not entirely sure what I should do with it now that I've built it.  There's not much non-commercial demand for something like that that I am aware of. I might be persuaded to license it for use commercially once there is a "go live" license for Whidbey.  I'm sure it will need some testing to work out issues.  I'll probably build a viewer using it and use it at work to get the kinks out of it.  Anyway, I thought it might be useful to capture how some of these features played out in a real scenario.

Lightweight Code Generation

I used attributes to annotate my record classes in order to define the "on disk" layout of the record.  I originally put the attributes on the properties of the record, but decided to move them to the class level so that I could define the fields that are only used for parsing, and not useful after that.  At runtime, I register the record types with the parser, which uses lightweight code generation to generate converters from unknown records to the concrete records.  If you're not familiar with LCG, it is essentially Reflection.Emit without the overhead of a dynamic assembly, module, or type.  If you're unfamiliar with Reflection.Emit, it is essentially generating executable IL code on the fly, which has may benefits over generating C# or some other language and running it through the compiler with CodeDOM or soemthing else. (If you're not familiar with IL, then this entry is somewhat irrelevant) Having dealt with assembly on lots of different instruction sets from 68000 to x86 to DSPs and microcontrollers, I must say that working in IL is wonderful.  I was a bit worried about the startup time for the parser, but it seems to happen very quickly.  I'll need to experiment more to come up with the overhead of the dynamic code.  Again, I was disappointed in the lack of debugging support in LCG.

Generics

Unfortunately, generics did not work into the equation near as much as I had hoped.  I did find them very useful in places where I would normally pass a Type.  Now I can have a much stronger contract on such methods using generic methods with constraints.  I must say that I love the generic collections.  Working with strongly-typed data without having to generate the classes is very nice.  I also like being able to do a custom sort with an inline anonymous delegate with closure-type semantics rather than have the overhead of a separate class with the code in a different place.

Iterators

Iterators came into play in several places.  In the pull-based record parser, it was simple to implement IEnumerable.  I believe it only took 3 or 4 lines of code.

Delegate type inference

I don't remember what the official name of this feature is, but instead of having to do something like SomeEvent += new EventHandler(SomeMethod), you can just do SomeEvent += SomeMethod.  This seems small, but I appreciated it quite a bit.

Visual Studio Enhancements

These were a very pleasant surprise.  I hadn't thought about the exercise as testing the VS enhancements.  The snippets were the most useful improvement in this project.  Implementing properties didn't make me want to rip my hair out. Just type 'prop' and hit tab and fill in the blanks.  The built-in snippets for things like exceptions, attributes, indexers, etc. all work really well.  The one for implementing an indexer/iterator as a nested class was very interesting as well. It was also easy to create my own snippets.  I also found the strongly-typed resources to be very handy.

The debugging stuff is awesome.  I love being able to mouse over variables and drill into them dynamically.  The little popup windows for exceptions are cool, but don't really give you any good information that you couldn't get before.

I found the refactoring support to be extremely useful, although it was a little hard to shift into the mode of making sure everything compiled all the time.  Before, I would jump around alot in the code, so I would leave things in a state where it didn't compile.  It worked great once I got used to it.

posted on Friday, April 08, 2005 10:22:28 AM (Pacific Standard Time, UTC-08:00)  #    Comments [3]
 Tuesday, April 05, 2005

Well, it looks like the Lady Bears are gonna win it all.  That's really exciting.  They really deserve it.  I played in the basketball band at almost every home game while I was at Baylor.  Just heard the 'bones playing Emperial March.  Cool to see the band still doing some of the things that Dave, Jeff, and I started while we were there.

[Update] It's now official

[Update] changed 'game' to 'band'. He he

posted on Tuesday, April 05, 2005 6:36:29 PM (Pacific Standard Time, UTC-08:00)  #    Comments [3]

CRW_2397867So, my recent drink of choice is also Robert Scoble's.  I found it to be one of a very small number of diet drinks that I can stand.  Among them are Diet Dr. Pepper and Diet Dr. B (a knock-off).  I find Diet Mug Root Beer to taste almost exactly the same as the regular version.

Robert, just don't leave it in the freezer and forget about it.  I wanted a cold one and the cans we're cold yet, so I thought a little freezer time would speed things up.  So, I forgot about it.  It was a mess.  It was pretty cool though.

posted on Tuesday, April 05, 2005 7:08:55 AM (Pacific Standard Time, UTC-08:00)  #    Comments [1]
 Monday, April 04, 2005

This is what happens if you break your XBox communicator and still want to play.  Dave broke the plastic part that rests on your ears, so he's using a headband to hold it onto his head.  He said he was really hot after playing a while. Hilarious. 

posted on Monday, April 04, 2005 7:41:37 PM (Pacific Standard Time, UTC-08:00)  #    Comments [2]

4th of July FireworksWell, it's a new month, and you know what that means.  That's right, another 1GB of photos to upload to Flickr.  Most interesting of the uploads this week is my full set of 4th of July fireworks pictures.  These are from two sessions of fireworks launching.  One out west of Belton with my brother and his in-laws, and another with Jen and Dave's family out in Copperas Cove. During the later session, we were much better prepared for taking photos, so they turned out really good.  My new digital processing techniques really brought out alot of detail as well.

I have now loaded all of my pictures back to the point where I got my Canon 300D, so next comes the flood of older pictures from my old Sony DSC-S70.

posted on Monday, April 04, 2005 7:51:42 AM (Pacific Standard Time, UTC-08:00)  #    Comments [3]

I had two projects over the weekend.  One was to get my bathroom ready to install a new bathtub.  The other was an experimental coding project.

The bathroom preparation went fairly well.  I ripped out all the cabinets and countertops.  I'm glad my brother showed up unexpectedly because that countertop was incredibly heavy.  We also got alot of the carpet ripped up.  I'm going to be putting down new flooring as well.

On the coding front, as an experiment in adopting new features in Whidbey, I implemented a binary file parser for Standard Test Datalog Format (STDF) files.  These files make up 99% of the data we work with at work and that fill our many-terabyte test result database.  We have a fairly complex parser and db loader framework, implemented in C# on 1.x.  It works very well, but it was written early on in our adoption of .net with little knowledge of what the CLR could do for us. So, my experiment was basically to see how new features in Whidbey, along with my now deep experience in .net, could make the parser better.

STDF is record-based.  The spec defines alot of records, and leaves room for user-defined records.  The new parser reads chunks of the file based on the record headers and produces "unknown records".  I define the record layouts using attributes on record classes.  Then, the parser uses LCG (lightweight code generation using DynamicMethod) to generate converters to read the content of the unknown records into the concrete record classes (based on the attributes).  The benefit of using LCG is that record types could be registered or removed on the fly and the GC could collect the generated code.  I could have just as easily implemented it using on-the-fly interpretation of the attributes.  I'll measure and see how the performance works out.  The parser is pull-based, meaning that you ask it for records, or alternately just "foreach" through them using an iterator-based IEnumerable implementation, which is pretty sweet.  On top of the pull-based parser, I built an event-based "processor" where a consumer can register to receive certain record types.  This is the model used in our current parser, but after the XmlReader vs. SAX discussions, I thought exposing the pull-based approach was the right thing to do.

I had a few challenges, which I think represent work for the next version of the CLR:

  • Endian-ness - To my knowledge the framework does not have any mechanism to work with binary data with non-native endian-ness.  The STDF is written in whatever endian-ness is native to the platform, so the parser must adapt.  This was a simple enough problem to solve, but now that most of the other gaps have been filled, endian-ness represents a hole in what the framework provides.
  • Generics' proliferation - Generics are great, and saved me tons of code, but they have not made their way into the rest of the platform where they could be leveraged.  For instance, if I create a RecordField, there's not a simple way to do something like BinaryReader.Read() to actually get one, so I was forced into tons of ifs and switches, and passing Types around to get the work done.  It just didn't feel right.
  • LCG debugging - From what I understand, this was cut from Whidbey.  The workaround for me was to have two generation paths.  One would do LCG, and the other would do traditional Reflection.Emit that could be debugged and PEVerified, etc.  The problem with this was the argument were not aligned between the two.  When doing the traditional Reflection.Emit, ldarg.0 would give you the "this" instance, which didn't exist in LCG.
  • Handler registration (Generics compatibility) - Ideally, record handlers should work with concrete record types, but the way generics work a Converter is not assignable to a Converter even though Mir : StdfRecord.  Of course implementing that would complicate many things.  Interestingly, delegate(UnknownRecord unknownRecord) { return new Mir(); } will satisfy both delegate types.  So, this was just frustrating that Generics didn't help me out in solving my record handler registration problems.  There may be a solution that I'm not seeing here because of my approach.  Any ideas?

Oddly enough, I spent about equal time on both projects, but I seem to have alot more to say about the later.

[UPDATE] I realized that the entry box swallowed some of my generics syntax, so I fixed that, as well as fixing some minor spelling and grammatical errors.

posted on Monday, April 04, 2005 6:57:16 AM (Pacific Standard Time, UTC-08:00)  #    Comments [6]