Brendan Enrick's Blog

Daily Software Development.


Try Writing Try Methods

by Brendan Enrick Wednesday, April 4 2012 11:00

When I say "Try Methods", I am of course referring to the common prefix "Try" on a method, which implies that the method is going to attempt to do what you're asking by using an output parameter for the operation and using the return value to indicate whether the attempt succeeded.

The common ones that people see in the .NET Framework are the TryParse methods, which attempt to parse something and if it can't be parse, they assign the default value to the output parameter and return false. If the succeed, the parsed value will be placed in the output parameter and the return value will be true. If the code failed, the convention is to use the type’s default value to assign to the output parameter. This lets you write code like this:

int someNumber;
int.TryParse(userInput, out someNumber);
// use the number entered or the default 0
int result = 1 + someNumber;

 

This is also great when you're going to be checking whether the method succeeded. In fact, you can use the try method directly in the if block, which usually makes things nice and clean. Here is an example of using them like that:

int someNumber;
if (int.TryParse(userInput, out someNumber))
{
    // Do something with someNumber
}
else
{
    // Invalid input: handle this case accordingly
}

 

Yes, you know all of this and have seen it before, however, are you writing these types of methods yourself or is your only experience with them the standard TryParse ones?

What I am trying to emphasize here is that you need to write your own Try methods in your code. You will thank yourself later.

Everyone can see the obvious benefit of not having to check for the default value to see if it the method worked. You also don't have to have ugly Try-Catch logic in your code. You get an if statement instead.

The real benefit of a writing a Try method has nothing to do with what I've already said. The most important benefit, in my opinion, is that you have a return value from it that isn't the value you are using for your logic. By having this return value for its success, you have to decide on how to handle the case where it failed.

There are important cases that might be forgotten, but having a return value means that I need to handle the return value. When I have it, I need to decide what to do with it. There may be a message I need to display to a user. There may be logging I need to do. I might be able to ignore that case. What is important, however, is that I thought about how to handle it. I had the chance to make sure that I handled the case correctly.

Create your own “Try” methods. I recommend looking into creating your own “TryParse”, “TryGet”, TryDelete”, and anything else that has a chance of failure that you may want to handle.

Comments

4/4/2012 12:38:31 PM #

Daniel White

I write web services to almost having a "Try Method". I never throw exceptions from the web methods. Each web method only return an enum with an appropriate result code. That way the client won't have to know what "Object not found" exception would mean to them. I just return "UnspecifiedError". Thats a clue then for the tracing to look closer.

Daniel White United States

4/4/2012 3:44:15 PM #

Erik

Personally, my sticking point with this approach is the sort of innate aversion I have to "out" parameters.  If I'm creating something like this, what I often wind up doing is returning some object that encapsulates success/failure as well as actual return value.  As a quick example (though not one I tend to favor), this might mean returning a nullable for a value type, and avoiding 'magic' values in this fashion.

Any thoughts on avoiding the out parameters, or does the semantics of that not bother you?

Erik United States

4/5/2012 10:58:00 AM #

Meta-Knight

I agree with Erik. I have many different Try methods in my codebase, but usually try to avoid having an "out" parameter, and instead return a default value or a nullable value if it fails. This usually results in shorter code.

Let's say we had a string extension method TryParseIntOrDefault which returns the parsed value as an integer, or 0 (default value) if it can't be parsed. Then you could write your first sample in one line:

int result = 1 + userInput.TryParseIntOrDefault();

Meta-Knight Canada

4/5/2012 1:17:54 PM #

Brendan Enrick

Yes, it will save 1 line of code if you don't use the output parameter, however, I prefer it to doing the null checks.

Output parameters don't bother me, but if they bother you, creating types that encapsulate the success or failure result or setting the value to null works. I like how obvious they make the requirement to consider the non-standard case.

I assume that in your approach, you just make sure to always check null on any object that comes back from a method with "Try" in the name. Which will also meet this requirement.

As long as you're using "Try" methods that aren't throwing exceptions and are handling the failure case nicely, I'm happy.

Brendan Enrick United States

Comments are closed