Click here to Skip to main content
Click here to Skip to main content

Prefix cast or as-cast?

By , 16 Aug 2012
 
I read today a nice article, from Kathleen Dollard, called To “as” or not to “as”. This is a pain-point for me on which I stumble often, so I decided to write this little rant.

I particularly liked a paragraph from the above-cited article :

One of the things that makes hard bugs hard is when there is a disconnect in time or space between the cause and the symptom. Time is time, space is lines of code, assembly placement, etc. Code can be written to minimize these disconnects. One of the ways to do that is to fail quickly. When application state becomes incorrect, yell about it immediately and rarely continue with the application in an invalid state. A null-reference exception at an unexpected time just makes code more difficult to debug.

I couldn’t express this as good as Kathleen did. Make no mistake I am quite biased in this comparison (direct-cast vs. as-cast). I kind of hate the abuse of the as operator.

Very often people turn to as instead of the direct (prefix) cast because:

  • They fear the InvalidCastException (strange, they don’t seem to fear the NullReferenceException)
  • They feel the syntax more fluent, closer to the human language.

I would consider the only valid case to use the as-cast is, just like Kathleen states, when a null value result is valid for the rest of the execution of the code. For the rest of the cases it’s just wrong.

This also promotes (doesn’t necessarily causes but promotes) bad practices like this :

public static void OnButtonClick(object sender, EventArgs e)
{
    var button = sender as Button;
    if (button == null)
    {
        return;
    }
    if (button.Tag == "somevalue")
    {
        // do something
    }
    // ...
}

In this example the event handler (which could be attached to more than one distinct button) simply forces under the rug a situation which would be abnormal (the sender not being a button) instead of releasing it so the developers could find it easier and debug it. A saner approach is :

public static void OnButtonClick(object sender, EventArgs e)
{
    var button = (Button)sender;
    if (button.Tag == "somevalue")
    {
        // do something
    }
    // ...
}

This brings me to another advantage of the prefix-cast : it produces shorter, clearer code.

In other cases the as abuse does more harm, hiding the source of a bug :

public void ProcessData(Entity entity)
{
    var person = entity as Person;
    UpdatePersonStatistics(person);
    // .. more code
}

public void UpdatePersonStatistics(Person person)
{
    NormalizeData(person);
    // .. more code
}

public void NormalizeData(Person person)
{
    person.Name = person.Name.Substring(0, 50);
    person.Address = person.Address.Substring(0, 100);
    // .. more code
}

Of course this is a contrived example full of bad practices but for now let’s focus on the as usage. Suppose the ProcessData method receives an instance of Category by mistake. Since Category inherits Entity the compiler will not complain.

The result is that there will be a NullReferenceException two methods further, in the NormalizeData method. If the cast was done with a prefix cast the error was a little bit easier to spot. This is confusing two-fold :

  1. The name of the exception suggests that a null reference was somehow obtained but in fact a real instance of Category was passed, not a null
  2. The error does not originate from the NormalizeData code but from the caller of the ProcessData

Summary

Use as only if a null result of the conversion makes sense for the flow of the execution. Otherwise use prefix cast.


License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Andrei Rinea
Software Developer (Senior) IBM, Business Analytics
Romania Romania
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionSubverting OOmemberJohn Brett17 Aug '12 - 1:53 
I always start with the position that casting to an object type is inherently an admission of failure. That failure may have been a failure of the language/CLR (e.g. ArrayList, but less so now with Generics), a failure of the framework (e.g. EventArgs sender), or a failure of design (e.g. any kind of switch (object.GetType()) construct).
 
The example given:
var button = sender as Button;
if (button == null)
is a classic subversion of OO design, in which the caller is responsible for defining the behavior of the object.
 
OTOH, using 'as' for interfaces I've always found more acceptable, since it gives us an opportunity to have 'optional' behaviors. E.g.
var container = sender as IComponentContainer;
if (container != null)
 /* iterate over the contained controls as well */
 
I'm still looking for alternatives and am optimistic that IoC can give me what I'm looking for (a cast-free code-base), but I'm not there yet.
AnswerRe: Subverting OOmemberAndrei Rinea17 Aug '12 - 3:29 
Very good points!

SuggestionMicrosoft practicememberClifford Nelson15 Aug '12 - 13:00 
Microsoft internal practice seems to be to use the cast, not the as keyword. I beleive that this is because of performance. You may want to mention using the Contract.Assert or Contract.Requires to ensure that during debugging ensure that a handler is not attached to a non-button. Makes more sence than checking the type, which should not be required in production.
SuggestionRe: Microsoft practicememberkornman0022 Aug '12 - 11:23 
Let's not forget that as operator can only perform reference/boxing conversions, where cast expressions can invoke user-defined conversions (another reason MS may internally use it in .NET). See the as operator's Remarks documentation[^].
 
This may lead to faster execution of casting. Another CP'er tried to document the performance differences[^] back in 2004...not sure if those numbers are still relevant today.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 16 Aug 2012
Article Copyright 2012 by Andrei Rinea
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid