Last considerations about generics

As we’ve seen, constraints will help in writing “type safe generic code” (not sure if this designation really exists. if it doesn’t, then I’ve invented Smile). But even with generics, there are still a couple of scenarios which might caught you by surprise. Lets start with casts and with a simple example:

class Generic<T> {
    public void DoSomethin(T something) {
        var aux = (String) something;
    }
}

The previous class won’t compile because there’s no way for the compiler to know that it’s possible to convert something into a String. At least, not when it’s compiling the generic open class! Notice that you can’t even apply a constraint to solve this problem. There is, however, a workaround (which isn’t really type safe):

class Generic<T> {
    public void DoSomethin(T something) {
        var aux = (String)(Object) something;
    }
}

Since any object can be cast to Object, then the compiler won’t complain about that first cast. The other cast (String) is now possible, though it might throw an exception at runtime. In fact, there’s a better option of doing the previous cast:

class Generic<T> {
    public void DoSomethin(T something) {
        var aux = something as String;
    }
}

Notice, however, that you’ll only be able to do this whenever you’re converting something into a reference type.

Since generic type arguments can be replaced by any concrete type, then you might be wondering how can you initialize a “generic” variable to its default value. The problem here is specifying its default value. I mean, if you’re talking about reference types, then it’s ok to set it to null. However, doing it with a value type results in a compile type error. To solve this problem, Microsoft introduced the default keyword:

class Generic<T> {
    public void DoSomethin(T something) {
        T aux = default(T);
    }
}

Now, the compiler is happy. When T is replaced by a reference type, aux is initialized with null. On the other hand, if T is replaced by a value type, then aux reference some memory space (big enough to save a value of that type) with all its bits initialized to 0. Btw, there’s also an interesting gotcha regarding the use of null: you can’t use it to initialize a variable, but you can use it with the operators == and !=. Here’s and example:

class Generic<T> {
    public void DoSomethin(T something) {
        if(something == null ) {
            //do something
        }
        else {
            //do something else
        }
    }
}

When T is replaced by a value type, the JIT compiler won’t emit the native code for the if part because a value type never is null.
Notice that if we had constrained T to a struct, then yes, we’d be getting a compile error on the if clause.

It’s also important to understand that comparing two variables of the same generic type results in an error if that generic type isn’t constrained to a reference type:

class Generic<T> {
    public void DoSomethin(T something, T somethingElse) {
        if( something == somethingElse) {
            //some code
        }
    }
}

If T were constrained to a reference type, the code would have compiled without any errors. However, constraining T to a a value type, will always result in an error. Since you cannot constrain T to a specific value type (a value type is always sealed and we’ve seen that we can’t do that because it’s more efficient to write code that uses directly that type), you’re limited to saying that it’s a value type. And this information isn’t enough to make the compiler do its work and emit the correct code for the comparison.

A final note: you can’t use generic type variables as operands (ie, you can’t use them with the operators +, –, *, etc.), making it impossible to write expressions which work for any numeric type. This is a tremendous problem, especially for those guys that work in the financial world…

And that’s it for now! Stay tuned for more.

Advertisements

~ by Luis Abreu on March 26, 2011.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

 
%d bloggers like this: