An anti-pattern: return w/ out

Eric Lippert, a member of the C# design team has an excellent little factoid about the C# cast operator and how some code can lead to surprising results.

I’d like to take a step back and examine the problematic code from a different angle. First, let’s see the code:

object result;
bool isDecimal = GetAmount(out result);
decimal amount = (decimal)(isDecimal ? result : 0);

Aside from the fact that the decimal cast here will not work at run-time, do you, dear reader, see anything suspicious about this piece of code?

The problem is that the GetAmount function uses an out parameter. What this effectively does is allow GetAmount to write back to our local result variable. The GetAmount function also returns a boolean value by the usual means, answering the question “is this amount a decimal”?

That first part of the code will work, but it makes the code less obvious and obstructs the purity of the code. That’s a somewhat subjective assessment but if all functions returned values using out then the code definitely would be much less readable.

So what to do here? We basically have the problem that we want to return two values: the amount and whether this amount is a decimal. Well, since C# 2.0, we’ve had nullable types. This means we can create a nullable type for any primitive (non-nullable) type. For example, a decimal is not nullable but we can create a variant that is: decimal? or Nullable<decimal> (the questionmark defines nullability). This means our decimal now has the potential to hold an extra value: null. We can use this value to designate whether the value is a decimal or not.

So let’s first change the above code to take out “out“:

decimal? temp = GetAmount();
decimal amount = temp.HasValue ? temp.Value : 0.0m;

That’s better and shorter. Can we make it shorter still? Allow me to introduce my new friend: the null-coalescing operator from C# 3.0:

decimal amount = GetAmount() ?? 0.0m;

The null-coalescing operator (??) will evaluate to the right side of the operator (0.0m in this case), if the left side of the operator happens to be null; otherwise it will evaluate to the left side.

We can even save 4 extra characters by using C# 3.0 type-inference:

var amount = GetAmount() ?? 0.0m;

So what happened here is this:

  1. we took out out
  2. we took out cast
  3. we took out two variables
  4. we took out two thirds of the code! (104 down to 33 characters)

In effect, we’ve seriously unspaghettified the code.

The reader might object: but what if we have 3 or more values we need to return. Well, in that case I have two answers:

  1. use objects, that’s what they’re there for, and
  2. use tuples, a new .NET Framework 4.0 type that allows easy return of multiple-values

This pattern here, of using nullable types is extremely useful and can help clean up code in many places. Not just for return values but also for parameters. They also have synergy with default parameters as introduced in C# 4.0.

I hope you’ll use this pattern instead and only use out parameters in very rare cases. In many cases, using out parameters is an anti-pattern.

Enhanced by Zemanta
About these ads

About xosfaere

Software Developer
This entry was posted in Software, Technical and tagged , , , , , , , . Bookmark the permalink.

2 Responses to An anti-pattern: return w/ out

  1. Eduard Dumitru says:

    Hi Bent,

    Just wanted to say thanks for the interesting fact about not solving a particular problem in a particular way.

    On the other hand, in Eric’s “factoid”, as I am sure you would agree, the problem you have underlined here was a mere excuse to show a fabulous mistake certain mathematician – programmers could make, involving essentially the deadly mixing of the cast operator when dealing with unboxing and the ternary operator bool ? Type1 : Type2 => Hypernym of Type1 and Type2, or the two types’ common super type.

    So, just to make an example, he didn’t actually need to involve out parameters to make the problem “fabulous”.

    Regards and thanks for being a geek :)

    • xosfaere says:

      Thanks for the comment Eduard. I agree with you; I just wanted to “riff” on Eric’s post because it reminded me of a pattern I don’t like -which is subjective because it has to do with readability, among other things; there are probably situations where out/ref parameters are the most convenient way to do things, I just personally try to avoid them because often they’re not needed and are just obscure ways to do multiple return values.

Leave a Reply

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

You are commenting using your 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