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

Reply via email to