Code formatter online

I’ve finally got round to doing it… the code I use for posting code for articles etc has now been transformed into a small ASP.NET app. It’s based on a VB.NET article. I converted it from VB.NET to C# using Instant C# (which worked very well – just a few gotchas, far fewer than last time I tried it) and then refactored it into a more object-oriented and cleanly layered structure. There’s now a WinForms application, and a separate class library, which the ASP.NET app uses.

If you want to use the results yourself, you’ll need the stylesheet I use. Unfortunately, between this blog, my home page, and the home for the application, I’m starting to get far too many copies floating around – I may need to rationalise at some stage, as making a change is becoming painful. Anyway, just reference the stylesheet in your page header, cut and paste whatever the app provides for you (between the textbox and the sample output) and you’re away.

The site is hosted by AspSpider.NET – free ASP.NET hosting. I only signed up with them yesterday, and everything seems to work pretty seamlessly, so it seems reasonable to acknowledge them in this post :)

The code can still be made a lot prettier, but it’s getting there. I was pleased with the ASP.NET side of things – obviously (being me) I did it all in a plain text editor, and the resulting .aspx page is 29 lines, with the code-behind weighing in at 60 lines. Nice.

Future plans for it:

  • A drop down list of languages (easy) (done, 17th Nov 2005)
  • A radio-button for the format type (css, html – easy)
  • Adding Java to the list of languages (hopefully fairly easy) (done, 17th Nov 2005)
  • Giving the code back to the Darren Neimke

CLI spec mistake with unboxing and enums

When looking over someone’s test code the other day, I happened to notice he was unboxing a boxed enum to an int. I was mildly surprised that he was able to do so – I thought you could only ever unbox to the exact value type that was “in the box”. Naturally, I consulted the spec. The C# spec is relatively woolly on the subject, unfortunately, but the CLI spec (partition three, end of chapter 4 for those who wish to look it up) is very clear. Here’s what it states under the Exceptions section, which is the interesting part – obj is the value to unbox, valuetype is the type we’re tring to unbox to:

InvalidCastException is thrown if obj is not a boxed valuetype (or if obj is a boxed enum and valuetype is not its underlying type)

That’s from the first edition of the spec. The third edition (still under consideration for approval by ISO/IEC) has this:

System.InvalidCastException is thrown if obj is not a boxed valuetype, or if obj is a boxed enum and valuetype is not its underlying type.

Seems harmless enough, right? Well, consider a situation where you have two enums, FirstEnum and SecondEnum. Then consider this (the code is in C#, but the generated IL is a direct translation – in particular, the types used for unboxing are preserved):

// Keep declarations out of the way to focus on the conversions.
object o;
int i;
FirstEnum x;
SecondEnum y;

o = 1; // The value of o is a boxed System.Int32
i = (int) o; // Conversion 1
x = (FirstEnum) o; // Conversion 2
y = (SecondEnum) o; // Conversion 3

o = (FirstEnum)1; // The value of o is a boxed FirstEnum
i = (int) o; // Conversion 4
x = (FirstEnum) o; // Conversion 5
y = (SecondEnum) o; // Conversion 6

Now, which of those versions should succeed? Reading absolutely literally, only conversion 1 should work. The others should all throw InvalidCastException. In all but conversions 1 and 4, the first part of the “or” clause in the spec is true (i.e. we’re trying to unbox to a different type) and in conversion 5, the second part of the “or” clause is true (the value is a boxed enum, and the type we’re trying to unbox it to isn’t the underlying type – it’s the real type!).

I know that’s reading the spec very literally, rather than taking the obviously intended meaning – but specifications should be precise documents. In fact, I’m not sure the intended meaning is so obvious anyway. Clearly conversions 1 and 5 should work (an “exact match” should always be valid) but what about 4? Should I be able to unbox an enum to an int? The way the spec is worded suggests that probably I should. What about the other way round (conversions 2 and 3), unboxing an int to an arbitrary enum which has int as its underlying type? Not so sure about that. As for conversion 6, unboxing one enum to a completely different one (which happens to share the same underlying type) – I think I’d actually rather that failed.

So, what happens? Under the current .NET implementations, all the conversions succeed. That pretty much means that’s the way the behaviour is going to have to stay, meaning I won’t be able to get my wish about conversion 6. Still, never mind – what’s important is that the spec matches reality. I believe it’s very hard to word this in the “single sentence” style they’ve tried for. I think I’d say:

System.InvalidCastException is thrown if none of the following valid conversions are applicable:

  • obj is a boxed valuetype (covers 1 and 5)
  • valuetype is an enum, and obj is a boxed value of the underlying type of valuetype (covers 2 and 3)
  • obj is a boxed enum with underlying type valuetype (covers 4)
  • valuetype is an enum, and obj is a boxed value of an enum with the same underlying type as valuetype (covers 5
    and 6)