Buckaroo .NET implementation
Buckaroo offers a simple solution for implementing iDeal payments on your website. In order to make use of the Buckaroo implementation, we need to write some code and apply configurations inside the p…
INDIVIRTUAL - TECHNISCH PARTNER IN DIGITALE DIENSTVERLENING
August 24, 2016
It’s a common enough wisdom in programming that you should never catch an exception that you can’t handle.
The reasons for this are well-known.
But on to the subject of my story. Today I came across a trap(!) that you can fall into even if you are keenly aware of all this. We generally try to avoid using exceptions as part of our day-to-day programme flow. Sometimes you want to test if something’s going to succeed, and depending on the outcome, go into one or other code branch. In terms of performance, an exception can be very expensive way of doing this. This is one of the reasons why it’s very common for types that offer a .Parse() method also to have a .TryParse() So instead of writing:
for (int i = 0; i < 9999999; i++)
{
try
{
double number = double.Parse(bigArray[i]);
ProcessNumber(number);
}
catch (Exception)
{
DoSomethingElse();
}
}
… you’d probably write it like this:
for (int i = 0; i < 9999999; i++)
{
double number = null;
if( double.TryParse(bigArray[i], out number)
{
ProcessNumber(number);
}
else
{
DoSomethingElse();
}
}
The big assumption here is that you are processing input data of some sort, which may or may not successfully parse to a double. In a big loop, with the chance of many exceptions, you really, really do want to choose the second approach over the first.
By contrast, today I was kicking the tyres on a popular web content management system, and reached a point where I had to decorate a class with an attribute and provide a GUID parameter. I used the “Create GUID” tool in Visual Studio, and pasted the result in. Some time later, after taking care of some other things, I tried running the code, and was faced with an exception.
[ArgumentOutOfRangeException: Specified argument was out of the range of valid values.]
Being unfamiliar with the system, it took me a while to figure out what had happened. It turned out that my finger had slipped while pasting the GUID, and there was an extra character at the end. (I don’t know about you, but I could stare at a GUID all day without spotting that.) The exception was coming up from the setter for the GUID attribute property on the attribute, so I decompiled the code and found something like this:
set
{
if (value == null)
{
this._guid = null;
return;
}
if (value.Length == 0)
{
this._guid = new Guid?(Guid.Empty);
return;
}
Guid value2;
if (Guid.TryParse(value, out value2))
{
this._guid = new Guid?(value2);
return;
}
throw new ArgumentOutOfRangeException();
}
So the programmer who’d written this was trying to do the right thing. By using TryParse, they were avoiding using an exception. However, circumstances alter cases, and in this case, I’d have preferred the exception. Once I’d realised it was one of my GUIDs, I was using the PowerShell to check them, and this is what I saw when I tested the culprit.
PS C:\Users\dominicc> [GUID]::Parse("2B48BBEE-202E-4B67-A18E-9B032111D7CCO") Exception calling "Parse" with "1" argument(s): "Guid should contain 32 digits with 4 dashes (xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx)."
So if they had used GUID.Parse() and just let it throw, I’d have had a much better message than the generic “out of range” text.
All in all, I think we should forgive the mystery programmer their error. It’s easily done, and I’ve written much worse code myself. The point I’m trying to make is that sometimes the right choice isn’t obvious. In this case, the GUID to be parsed would be checked in to my code repository, and once my own code is debugged, it’s not going to change. The exception would be truly exceptional. This is a very different circumstance to processing input data in a big loop, and so a different technique is called for. Exceptions are useful. They are there for a reason, and sometimes an exception is what you want.