Using conversion operators to create flexible types

February 20, 2012

Follow along with me. Have you ever had a situation where you had to represent some conceptually complex or flexible value in a class? For instance, the the concept of “hours”? Maybe you would start off simple with something like:

public class Foo
{
    public decimal Hours { get; set; }
}

//usage
foo.Hours = 1;
foo.Hours = 1.5m;

You were clever to note that hours may be used as whole numbers or fractions, so you made sure  you could assign int and decimal values. But it turns out your data is more complex than that. You also must account for string representations of hours, such as “1:30” (one hour and thirty minutes).

Easy enough. It’s probably time to create a custom class or struct to encapsulate all that. If you’re not familiar with implicit or explicit conversion operators, you may end up with a simple class with overloaded constructors that accept int, decimal, or string, so that it could be used like this:

hours = new Hours(1);
hours = new Hours(1.5m);
hours = new Hours("1:30");

decimal hoursAsDecimal = hours.Value;

It works. But this is kinda lame. Wouldn’t it be cool if you could just do something like this:

hours = 1;
hours = 1.5m; 
hours = "1:30";

decimal hoursAsDecimal = hours;

You can!

Understanding conversion operators

To quote MSDN: C# enables programmers to declare conversions on classes or structs so that classes or structs can be converted to and/or from other classes or structs, or basic types. Conversions are defined like operators and are named for the type to which they convert. Either the type of the argument to be converted, or the type of the result of the conversion, but not both, must be the containing type.

Here’s a basic Hours struct that has just one conversion operator:

public struct Hours
{
    private readonly decimal _hours;
    private Hours(decimal hours) { _hours = hours; }

    //implicit decimal to Hours conversion operator
    public static implicit operator Hours(decimal value)
    {
        return new Hours(value);
    }
}

This implicit operator is specifying that types of decimal can be implicitly converted into types of Hours, and the method body is how the conversion is performed (in this case, decimal is the underlying type, so it just returns a new Hours instance).

To allow other values to be converted, just specify additional implicit operators:

//implicit int to Hours conversion operator
public static implicit operator Hours(int value)
{
    return new Hours(value);
}

//implicit string to Hours conversion operator
public static implicit operator Hours(string value)
{
    //Parse() is the private method of Hours responsible for
    //converting the string to a decimal. It's omitted for brevity
    return Parse(value);
}

Switching things around

Every operator above defines how a particular type can be converted into the custom type Hours, but what about the other way around? How can we make Hours directly assignable to a decimal type? All you have to do is flip it around.

//implicit Hours to decimal conversion operator
public static implicit operator decimal(Hours value)
{
    return value._hours;
}

Again, this is defining that the type Hours can be implicitly converted into type decimal. The net result of this and the other operators defined above is that you can write super flexible and clean code:

hours = 1;
hours = 1.5m; 
hours = "1:30";

decimal hoursAsDecimal = hours;

A quick note about explicit operators

You can also make operators explicit. They work the same way, but require an explicit cast to work.

//explicit decimal to Hours conversion operator
public static explicit operator Hours(decimal value)
{
    return new Hours(value);
}

//usage
hours = (Hours) 1.5m; //explicit cast from decimal to Hours

hours = 1.5m; //compile error, "cannot convert decimal to Hours"

Because of this, implicit operators are generally preferred, but if you want callers of your code to be explicitly aware that they must cast properly you can do so.

Next time you find yourself creating a custom chameleon-like type that must be assignable to or from several different types, consider encapsulating all of the conversion code by putting it into the type and then creating implicit or explicit conversion operators to make the calling code clean, easy and flexible.

Don’t code in anger, man

February 17, 2012

I’m sorry. I knew it would come to this as soon as I started. But I didn’t care. In my blind rage from having to deal with one of the crappiest off-the-shelf products I’ve ever used, I started slinging code to replace it. Actually, not even to replace it, but just to prove I could build a better system for my needs.

I started building a simple CMS platform with ASP.NET MVC and began blogging about it (refer to the build-your-own-cms tag for the posts). These posts quickly became some of the most popular ones on my blog. Everything was great, and I was actually churning out a product that was accomplishing my goals (truth be told, it was really quick & dirty and needs a lot of work to become anything).

The problem was that I hated it.

Angry sammich  :http://www.flickr.com/photos/psycholabs/4009610672/

I don’t particularly give a damn about managing website content. Sure it’s an interesting challenge and one that may stare me in the face again. But right now I couldn’t care less. A year ago when I was hell-bent on completing this CMS platform of mine, I thought I cared. But I was only coding out of frustration. Eight, nine, ten hour days at work plugging leaks and duct-taping the software I had to support led me coming home just to boot up my pc to code my own system for several hours more a night.

I wasn’t coding for work. And I sure wasn’t coding for fun. I was coding out of anger and frustration with some perverse idea that if I completed my mission it would somehow make me victorious. Whatever.

But then a miraculous thing happened. I got a new job and didn’t have to support a CMS ever again. My interest in my project dropped to zero. I haven’t written a line of code for it since then.

I knew this was going to happen.

If you’ve been waiting for follow-up posts on my CMS series, I’m sorry to say that you may have to wait a while. While I certainly may have learned a thing and honed my skills during the process, it was largely a waste of time and energy. And then I went and blogged about it and let the three (two?) people down who were eagerly awaiting additional posts. Sorry, guys. I’ve learned my lesson.

Don’t code in anger, man.

Tags: coding, anger, cms
Categories: Miscellaneous

Metro vs Desktop: the opposing Windows 8 paradigms

December 20, 2011

[Note: this post was published in December 2011 and is commentary on the Windows 8 Developer Preview. It is assumed Windows 8 will change drastically as Microsoft continues development of it. I can only hope that the information below turns out to be wholly inaccurate once Windows 8 is released.]

In my previous post I discussed some major reservations I have with Windows 8 and specifically how the new Metro paradigm clashes with the traditional Windows desktop.

IE10 Metro will not support plugins on Windows 8

One thing I learned last week at the Dallas State of .NET: The Road To Windows 8 event is that Internet Explorer 10 in “Metro mode” does not support plugins (So no Flash. No Silverlight even!). Of course, plugins work just as expected in “Desktop mode”.

That a user even needs to comprehend the fact that Windows 8 really has two versions of IE and other programs is enough to spur intense discussion. But that’s not my concern here. It’s something else.

The Metro side of Windows 8 works similar to iOS and Android. It’s an OS assumed to be on hardware with limited resources, and so unlike desktop operating systems, only one application can be open at a time - all others are “suspended”. You can see that in Windows 8’s cool new task manager:

Windows 8 task manager

Of course, this only applies to Metro apps. Regular Desktop apps run the same way they always have. That is, they hog resources until you close them, even when you’re doing something else. Both paradigms are great on their own, but this is where Window 8’s schizophrenia can cause some serious conflicts and confusion, as I’ll demonstrate…

Let me lead you on a little picture story

Rather than rehash specs and facts, it thought it would be more effective to tell this one as a story.

It’s late 2012, and we’re chillin with our sweet new Intel Touch Ultrabook running Windows 8. What a perfect device to play FarmVille with!

Let’s boot the device up to the beautiful new Start menu app. We’ll click on that “e” icon to launch IE10.

Windows 8 start screen

The new Metro mode IE loads up, we log in to Facebook, ready start playing FarmVille. OH NOES! No Flash? (You can attempt to install Flash here, and it’ll let you try. But it won’t work. Thank me later.)

Windows 8 IE Metro does not allow Flash

Geez, lets go back and open up IE in Desktop mode. Now, to get to Desktop IE we need to stop by the Start screen – again – and click the IE icon – no, no – click on the Desktop icon.

Windows 8 Start screen

Ahh, the Windows desktop. So yesterday, eh? Let’s launch Desktop mode IE.

Windows 8 desktop

FarmVille at last!

Windows 8 IE 10 in desktop mode supports Flash

While we’re waiting for some crops to grow, lets go practice some scales! Back to the start screen.

Huh. That’s funny. The FarmVille music is still playing in the background. Let’s launch the piano app. do-do-dah-de-do--do!

Windows 8 Start screen

Umm. The FarmVille music is still playing. This could be distracting. We could mute the sound in FarmVille, but, ah well. That’s cool. We can play along!

Windows 8 Piano app

Hmm. Why is thing so sluggish? The sound is clipping and sometimes it doesn’t play the note right when we hit a key. It’s like we don’t have enough resources to use this app.

Wonder what the task manager says. Holy Crap! FarmVille! Our Resources!!

Windows 8 Task Manager

(Yes, the numbers above were ‘shopped, but it could happen.)

You can see above the Piano app nicely suspended itself, but FarmVille has been on the whole time. It’s certainly clumsy to be bouncing between apps that are managed completely differently.

The point of the story

In its current form, Windows 8 it attempting to glue together two completely different OS paradigms, and it shows. Metro apps act one way, Desktop apps act another, both with quirks that can negatively affect your experience on both sides.

I’m still sympathetic to the idea of bringing the full blown windows OS to a tablet or ultra-portable notebook device, but I do not like the way Microsoft has done it so far. Both opposing personalities of this OS are screaming for attention and it is awkward to have to manage each of their shortcomings.

I’d honestly rather have a system with 2 entirely distinct partitions, where I can boot into Metro mode when I’m on the go and boot into Desktop mode when I’m at my desk. Having them both running at the same time causes too many problems and doesn’t even solve any to begin with.

About Kurt

I'm a senior consultant at Headspring in Austin, TX. My passion is creating web-based applications that are well crafted and solve real problems for real people. Want to know more? Check out my about page.