Bookmark and Share

TryParse vs Convert

by KodefuGuru 24. June 2010 01:41

Since I’ve been coming out against out params, I sometimes get asked about the TryParse pattern. My typical response is that the most egregious offenses of out param usage occur when there is more than one, but even one should be avoided. However, I was recently presented with a more specific question: “lets say you had to pick up a query string param in WebForms/ASP.NET and make it an Int32... would use Convert or TryParse?” This is a very practical question, and given the choices it is interesting to examine for the best practice.

TryParse

int index;
int.TryParse(Request.QueryString["index"], out index);

This version isn’t so bad since it requires no conditional processing. The problem with the TryParse method is the out parameter, which requires the initial declaration of variable whether or not you want or need it. This also prevents it from being used in a declarative statement, since the return value is whether the value was parsed. This can be used declaratively using the ternary operator, but it is rather odd since the result is already defined. Many people opt to use imperative logic instead, testing for !<t>.TryParse.

Here’s are examples of non-zero default value. The first using an if statement and the second with the ternary operator.

int index;
if (!int.TryParse(Request.QueryString["index"], out index))
{
    index = 1;
}
int index;
index = int.TryParse(Request.QueryString["index"], outindex) ? index : 1;

Convert

var index = Convert.ToInt32(Request.QueryString["index"]);

Convert is more declarative in this form, but it has a fatal flaw. If the string being parsed is an invalid value (not null, but something like “asdf”), then it will throw an exception. Exceptions are expensive, and it requires wrapping the code in a try… catch block since the exception is typically meaningless aside from preventing the assignment. Perhaps the above statement would be better expressed as:

int index = 0;
try
{
    index = Convert.ToInt32(Request.QueryString["index"]);
}
catch { }

Yuck.

Maybe

In the response to the question on which method of parsing the query string param I would use, I rejected both typical solutions. They both have flaws I find distasteful. Why not parse the string and return a Nullable<T> so the caller can decide what to do with it?

int index = Maybe.ToInt32(Request.QueryString["index"]) ?? 0;

Simple and declarative. Maybe’s methods wrap the TryParse methods since they appear to be more efficient than Convert’s methods. The idea is that complexity should be hidden, and code should be made more declarative. I believe the Maybe class achieves it. The name was chosen because a non-generic Nullable class already exists, and Maybe seemed a sound choice since it may be a value or it may be nothing.

Conversion Failures

The typical conversion failure use case is to assign a default value. However, additional logic is sometimes necessary. With TryParse, you test the return value for false. With Convert, you catch the exception. With Maybe, you test for null.

int? result = Maybe.ToInt32(Request.QueryString["index"]);
if (result == null)
{
    // Failure processing
}

Since it is sometimes necessary to know if a the parsing was successful, I didn’t opt to create a ParseWithDefault method.

Download the source code from kodefu.codeplex.com.

Bookmark and Share

Get Rid of out Parameters

by KodefuGuru 9. June 2010 22:38

An anachronism of the procedural world, out parameters have no place in object-oriented or functional APIs. Here are three ways to rid yourself of them.

The Example

I have created a simple program that calls a method that divides a number and returns the quotient and the remainder.

static void Main(string[] args)
{
    int quotient;
    int remainder;
    Div(16, 3, out quotient, out remainder);
    Console.WriteLine("quotient: {0}", quotient);
    Console.WriteLine("remainder: {0}", remainder);
}

static void Div(int dividend, int divisor, out int quotient, out int remainder)
{
    Contract.Requires(divisor != 0);

    quotient = dividend / divisor;
    remainder = dividend % divisor;
}

The output from this program is:

quotient: 5
remainder: 1

The method needs to return two separate values, hence the use of two out parameters. This makes perfect sense from a procedural coding style.

The Object Oriented Way

Object oriented methodology dictates that values should be represented by objects. These two integers can be represented by one value, a DivResult, which uses a small amount of memory. Therefore, I will create a DivResult struct.

public struct DivResult
{
    int quotient;
    int remainder;
    
    public int Quotient
    { 
        get 
        { 
            return quotient; 
        } 
        set 
        { 
            quotient = value; 
        } 
    }

    public int Remainder 
    { 
        get 
        { 
            return remainder; 
        } 
        set 
        { 
            remainder = value; 
        } 
    }

    public DivResult(int quotient, int remainder)
    {
        this.quotient = quotient;
        this.remainder = remainder;
    }
}

Now the program is object-oriented.

static void Main(string[] args)
{
    var result = Div(16, 3);
    Console.WriteLine("quotient: {0}", result.Quotient);
    Console.WriteLine("remainder: {0}", result.Remainder);
}

static DivResult Div(int dividend, int divisor)
{
    Contract.Requires(divisor != 0);

    var quotient = dividend / divisor;
    var remainder = dividend % divisor;

    return new DivResult(quotient, remainder);
}

Something I find interesting about this approach is that you could write a custom iterator that returns dividend and divisor pairs for the DivResult.

Tuples

The .NET Framework 4 introduces the Tuple type, which is an ordered list of elements. We need to return two integers, and this is known as a pair of ints… or in tuple terms, a Tuple<int, int>. Here’s how to do that.

static void Main(string[] args)
{
    var result = Div(16, 3);
    Console.WriteLine("quotient: {0}", result.Item1);
    Console.WriteLine("remainder: {0}", result.Item2);
}

static Tuple<int, int> Div(int dividend, int divisor)
{
    Contract.Requires(divisor != 0);

    var quotient = dividend / divisor;
    var remainder = dividend % divisor;

    return Tuple.Create(quotient, remainder);
}

Creating a tuple is as simple as calling Tuple.Create with necessary parameters. Tuples are great for returning multiple types within the context of a method or a small program. The downside in C# is the loss of context. Notice that in order to access the values, we have to use Item1 and Item2 rather than Quotient and Remainder.

Dynamic

The dynamic keyword is a new feature in C# 4 that gives us late binding. In the context of CLR types, it allows us to do something we couldn’t do in C# 3 without resorting to reflection: return anonymous types from a method.

static void Main(string[] args)
{
    dynamic result = Div(8, 3);
    Console.WriteLine("quotient: {0}", result.Quotient);
    Console.WriteLine("remainder: {0}", result.Remainder);
}

static dynamic Div(int dividend, int divisor)
{
    Contract.Requires(divisor != 0);

    var quotient = dividend / divisor;
    var remainder = dividend % divisor;

    return new { Quotient = quotient, Remainder = remainder };
}

This has the benefit of allowing us to access the properties by their name but without type safety.

Update: A commenter (Ram) posted another way of doing this. Down the Functional Rabbit Hole explores this, and in my opinion is the best solution.

Conclusion

There is no reason to use out parameters in your own frameworks. C# is still primarily an object-oriented language, and when faced with a need to return more than one result a class or struct should be created. I presented two other ways of achieving the elimination of out parameters because it may not be desirable to create extra classes when there is no opportunity for reuse.

You will need to use out parameters when interfacing with third party libraries. This is unavoidable, but the impact can be minimized by creating a proper, object oriented wrapper around the third party library.

Bookmark and Share

ref on Reference Type?!

by KodefuGuru 12. June 2009 17:02

I recently came across a piece of code that had almost every parameter for every method marked with the ref keyword. This keyword is primarily used to pass a value type by reference, but this one even had reference types marked with the keyword. This made me wonder, why exactly would you ever want to pass a reference type as a ref parameter? Page Brooks and I discussed this at a user group meeting earlier in the week, but neither of us had an answer.

So, I turned to that ever-trusty resource, the MSDN Library. The trick is that passing by ref allows you to change the reference. Take this code for example:

class Program
{
    static void Main()
    {
        var message = new Message("Created by Main");
        Console.WriteLine(message.Text);
        Method(message);
        Console.WriteLine(message.Text);
    }

    static void Method(Message message)
    {
        message = new Message("Created by Method");
    }

    class Message
    {
        public string Text { get; set; }
        public Message(string text)
        {
            Text = text;
        }
    }
}

This will have the following output:

Created by Main
Created by Main

The reason “Created by Method” isn’t printed is because the parameter message was given a new reference. The message variable in Main() has its original reference. Now let’s see what happens when we change Method() to use a ref parameter.

class Program
{
    static void Main()
    {
        var message = new Message("Created by Main");
        Console.WriteLine(message.Text);
        Method(ref message);
        Console.WriteLine(message.Text);
    }

    static void Method(ref Message message)
    {
        message = new Message("Created by Method");
    }

    class Message
    {
        public string Text { get; set; }
        public Message(string text)
        {
            Text = text;
        }
    }
}

Now our output looks like this":

Created by Main
Created by Method

The ref keyword has modified Method() so that now it will allow the reassignment of message.

Wait, isn’t that just like the out keyword?

Actually, it’s almost identical to the out keyword. I can even replace ref with out in the above example and it will work exactly the same. However, there is one difference: you need to pass an assigned variable with ref, but you can pass an unassigned variable with out. It’s semantically odd to expect an out parameter to be used as input, although nothing prevents you from doing this. It would be best to stick with ref if you wanted in/out.

Now that I’ve explained the behavior one gets using the ref keyword with a reference type, allow me to make a bold claim. The ref and out keywords are code smells.

There’s almost no reason to ever use the ref or out keywords with a reference type. In fact, in the code where I noticed the ref keywords littered everywhere, it wasn’t reassigning parameters in the methods. The ref declarations were merely a waste of space that caused the Spock eyebrow to raise. If you are reassigning the parameter, I recommend that you take another look to see if it can be done another way. For example, the ref version of the method could easily be refactored to return a message object that is assigned to the message variable:

static void Main()
{
    var message = new Message("Created by Main");
    Console.WriteLine(message.Text);
    message = Method(message);
    Console.WriteLine(message.Text);
}

static Message Method(Message message)
{
    return new Message("Created by Method");
}

I feel that this code is much clearer than using ref. In the method that’s making the call, Main(), it’s clear that message is being reassigned. In the ref version, you have to look through Method() to see whether or not it is being reassigned.

The keywords are there because there are situations where they are useful; DateTime.TryParse() comes to mind. However, like most cool tech in C#, it can be abused.

KodefuGuru.GetInfo()

Chris Eargle
LinkedIn Twitter Technorati Facebook

Chris Eargle
C# MVP, INETA Community Champion


MVP - Visual C#

 

INETA Community Champions
Friend of RedGate
Telerik .NET Ninja
Community blogs & blog posts

I am a #52er

I have joined Anti-IF Campaign


World Map

Tag cloud

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2010