I came across these two posts on Eric Lip­pert’s blog yes­ter­day which I found very interesting:

Rep­re­sen­ta­tion and Identity

Cast oper­a­tors do not obey the dis­trib­u­tive law

The blog posts go into a lot of details but long story short, if you box a value type you can’t unbox it to another type:

image

It would result in an Invalid­Cas­tEx­cep­tion, and the big ques­tion is, if there exists a con­ver­sion from int to long why can’t the run­time work it out?

Well, con­sider three sim­ple types A, B and C, where B inher­its from A and C pro­vides an explicit con­verter from A:

public class A {}
public class B : A {}
public class C 
{
    public static explicit operator C(A a)
    {
        return new C();
    }
}

There exists two types of con­ver­sion which you can achieve using the Cast­ing operator:

var b = new B();
var a = ( A ) b; // inheritance-based conversion, equivalent to var a = b as A;
var c = ( C ) a; // operator-based conversion

In essence, the inheritance-based con­ver­sion is just show­ing the same object in a ‘new light’, whereas the operator-based con­ver­sion requires a spe­cial treat­ment on a case-by-case basis in the form of con­ver­sion methods.

Inheritance-based Con­ver­sion

(representation-preserving)

Operator-based Con­ver­sion

(representation-changing)

New object is not con­structed con­structed
New vari­able points to orig­i­nal object new object
Chang­ing the new variable changes the orig­i­nal object doesn’t change the orig­i­nal object
Con­ver­sion is fast slow

A box value type is an object, so as far as the com­piler is con­cerned it could be any­thing. There­fore by allow­ing a boxed value type to be cast to a dif­fer­ent type you intro­duce new chal­lenges to the compiler:

  1. it needs to gen­er­ate more code at run­time (from CIL to machine code by the JIT-Compiler) because the com­piler needs to check if it needs to call a con­ver­sion method after unbox­ing the boxed value type.
  2. it also needs to work out which con­ver­sion method to call, this requires sig­nif­i­cant amount of analy­sis giv­ing that there can be an arbi­trary num­ber of con­ver­sion meth­ods (both built-in and user-defined) on arbi­trar­ily many types.

Unfor­tu­nately the cost of meet­ing these chal­lenges is per­for­mance, and the sen­si­ble default was to be “fast and pre­cise” but still allow­ing this type of con­ver­sion through the Con­vert class.

Part­ing thoughts…

Towards the end of the post there was a warn­ing to those look­ing to abuse the new dynamic type sup­port in C# 4 ;-)

“…if the argu­ment to the cast is of type “dynamic” instead of object. The com­piler actu­ally gen­er­ates code which starts a mini ver­sion of the com­piler up again at run­time, does all that analy­sis, and spits fresh code. This is NOT FAST, but it is accu­rate, if that’s what you really need. (And the spit code is then cached so that the next time this call site is hit, it is much faster.)…”

Share

Leave a Reply