The Right Approach to Exceptions

Jim Hewes jimhewes at gmail.com
Sun Feb 19 12:31:16 PST 2012


On 2/19/2012 3:40 AM, deadalnix wrote:
>
> Well, I think you are messing up between contract and exception. Wrong
> parameters is a contract problem, not an exceptionnal situation.
>


Here is an example of what I'm getting at. Let's say you have a 
Dictionary class. This class has a function called Get(key) which will 
retrieve an item from the dictionary. But the item may not be found in 
the dictionary. Should you throw an exception if the item isn't found. 
Well, the “exceptional situations” crowed will say that since it's 
common for an item to not be found, this isn't an exceptional situation 
and you should therefore not throw an exception. An item not being in 
the dictionary is part of the normal program flow and you don't want 
exceptions firing off during normal program flow. But then what? You 
return false or a NotFound error code? But then do I need to check for 
this error every time I extract an item from the dictionary? You're 
losing the benefit that exceptions bring.

Here is the way I'm thinking exceptions are related to contracts. I 
think you need to better define what the function is expected to do and 
not do in order to know when an exception is thrown. I can define 
Get(key) in two ways. I can declare that the item associated with 'key' 
must exist in the dictionary. Therefore if the item is not in the 
dictionary then the contract of the caller is not fulfilled, it's an 
error, and an exception is thrown. But how is the caller supposed to 
know an item is not in the dictionary before calling Get(key) and thus 
avoid exceptions? One solution is to provide a second function called 
ItemExists(key). You can call this before calling Get(key). 
ItemExists(key) is then defined to return true of false depending on 
whether the item is in the dictionary. It doesn't throw an exception if 
the key doesn't exist because it's main job is to determine if the key 
exists or not.

Obviously this causes bad performance because the item must be looked up 
twice each time you retrieve it. So the second way to deal with the 
problem is to define the contract of Get(key) differently such that the 
argument 'key' is not required to exist in the dictionary. To 
distinguish this function, call it TryGet(key). This will return false 
if the item is not in the dictionary. (But it may still throw an 
exception for other errors such as a null argument or whatever.)

So I think whether an exception is thrown depends on the function's 
contract. It does not have to do with errors being “exceptional” or not. 
Perhaps I should not even be using the term contract at all and should 
just say that functions need to be clearly defined. I don't know. I'm 
always open to learning more about exceptions to create better designs, 
which is partly why I jumped on this topic (and now so selfishly pulled 
it off topic). If anyone thinks I'm totally off base then tell me why 
and I might learn something.

By the way, the example I was using actually exists in the .NET 
Framework and uses both approaches. Look at the 
System.Collections.Generic.Dictionary class. Instead of Get, ItemExists 
and TryGet, the functions are named respectively:

Item          (bracket syntax this[])
ContainsKey
TryGetValue

(see http://msdn.microsoft.com/en-us/library/s620ab8x.aspx)

The KeyNotFoundException is only thrown by the Item property. So, I just 
put this out there as an example of when a seemingly “non-exceptional” 
case can use exceptions depending on the contract of the function.

Jim


More information about the Digitalmars-d mailing list