for each cast

Recently I stumbled over code like this:

class Bar
{
    void DoBar()
    {
    }
}

interface IFoo
{
    void DoFoo();
}

class Program
{
    static void Main(String[] args)
    {
        List<Bar> bars = new List<Bar>();
        foreach (IFoo foo in bars)
        {
            foo.DoFoo();
        }
    }
}

One would think the foreach statement above will not compile. The list can contain items of type ‘Bar’ but the foreach statement wants to iterate through IFoos – an interface Bar clearly does not implement. However that code will compile. Let’s have a look at a code line similar to the code the foreach statement might execute internally on the first element:

IFoo foo = bars.First();

This code will not compile. Phew luckily our world view is somehow still intact. The error the compiler is giving is: “Cannot implicitly convert type ‘Bar’ to ‘IFoo’. An explicit conversion exists (are you missing a cast?)” which already gives us a hint in which direction the journey goes. The compiler basically tells us: I would compile that for you if you add a cast to the statement. And indeed:

IFoo foo = (IFoo)bars.First();

compiles. Why does the compiler allow us to cast an object of type “Bar” to “IFoo”? Well the answer is easy: Because a derived type of Bar could implement IFoo.

class Bar2 : Bar, IFoo
{
    void DoBar()
    {
    }

    public void DoFoo()
    {
    }
}

...

    Bar bar = new Bar2();
    IFoo foo = (IFoo)bar;

Whether you can really cast “Bar” to “IFoo” or not, cannot be determined by the compiler at compile time. In fact it will be determined by the CLR at runtime. If the variable “bar” holds a reference to a “Bar” object the cast to IFoo will throw an InvalidCastException when excuting that code.
Now looking at the foreach statement it becomes clear that casting to “IFoo” is exactly what foreach implicitly does for the user and leads to perfectly valid code as we have seen. Nevertheless although it might be valid code it might not be want we want. To navigate around this behavior we have two options:

  1. Declare “Bar” as sealed – Declaring “Bar” as sealed will make it possible for the compiler to detect a problem with the cast to “IFoo” at compile time. The first example will not compile.
  2. Use the OfType<> extension method on IEnumerable – Using the OfType<> operation returns only those elements which are matching a certain type.

Flattr this!

One thought on “for each cast

  1. You said “Why does the compiler allow us to cast an object of type “Bar” to “IFoo”? Well the answer is easy: Because a derived type of Bar could implement IFoo.” Though that’s true, this explanation does not actually get down to the language design concerns that explain why what looks like it should be an implicit conversion actually has the same semantics as a cast.

    The answer is: the foreach loop was invented before generics. The designers knew that it would be common for users to want to “foreach” over an ArrayList that only contained strings, and so it is natural to write “foreach(string address in addresses)” where addresses is an ArrayList.

    A cast means that the developer knows something that the compiler doesn’t: that this thing of compile-time type object is really of string. The same goes for collection types: the foreach loop means that the developer knows something that the compiler doesn’t: that this thing is a collection of strings, not arbitrary objects.

    Had the foreach loop been designed after the invetion of generic collections it is likely that the foreach loop would do an implicit conversion to the loop variable type, not an explicit conversion, because in a world with generics it is far less common to have a collection of objects when you mean for it to be a collection of strings.

Leave a Reply

Your email address will not be published. Required fields are marked *