5

What type of exception should I throw?

I have a console class which describes rectangle of cells which a user can index by passing in a coordinate:

width, height = 80, 25
console = Console.new(width, height)

x, y = 2, 5
point_on_screen = Point.new(x, y)
console[point_on_screen] = 'a'

I am now wondering what types of exception to throw when an index occurs out of bounds . That is, outside of the (constant!) domains x:[0, width] and y:[0, height]. I could throw a RangeError or an ArgumentError *.

  1. Does it matter which type of exception to throw as long as the error message is useful?
  2. Should I use the same exception type for both the construction of the console and the indexing? Are the two really semantically different?

* returning a kind of out of bounds object is possibly a better option - something like a Null Object Pattern - but not what I am wondering about here.

ArgumentError

One option is to throw an ArgumentError because the argument is obviously wrong, dimensions can never be non-negative. This is what I throw in example 1, because we ought to know in advance that the dimensions should be non-negative.

Example 1:

console = Console new(-3, 4) # Argument error

RangeError

Another option is to throw a RangeError because the argument is out of the valid range. I use these for indexing. The argument is always out of range if x < 0, but if x ≥ 0 then it depends on the width of the console if the x is in the domain.

Example 2:

console = Console.new(20, 40)
pt = Point.new(-3, 4)
Console[pt] # RangeError
5

Does it matter which type of exception to throw as long as the error message is useful?

In cases like this, I often defer to the official docs for definitions and usage examples.

The docs for RangeError are a bit terse:

RangeError
Raised when a given numerical value is out of range.

[1, 2, 3].drop(1 << 100)
raises the exception:
RangeError: bignum too big to convert into long

And although the docs for ArgumentError imply encouragement towards a more specific Exception, one of the examples (in bold below) certainly seems like a potential match for your use case:

ArgumentError
Raised when the arguments are wrong and there isn't a more specific Exception class.

Ex: passing the wrong number of arguments
[1, 2, 3].first(4, 5)
raises the exception:
ArgumentError: wrong number of arguments (2 for 1)

Ex: passing an argument that is not acceptable:
[1, 2, 3].first(-4)
raises the exception:
ArgumentError: negative array size

Generally speaking, Argument-type exceptions are a clear and expected way to convey to the caller that they've supplied some invalid parameters.

Regarding your mention of "... as long as the message is helpful...", I say yes, absolutely. Always try to include a meaningful message when you raise an error.

Regarding the null object alternative: Personally, I'd encourage you to explicitly raise the error rather than return a null object (or some other out-of-bounds indicator). Code built with this pattern is plagued by constant null checks, and inevitably a null object will escape your safety nets and wreak unexpected havoc on your program.

When I'm working with software that routinely returns nulls or special values as a "something went wrong" indicator, I need to spend additional mental cycles to make sure I'm checking all responses, and that I'm looking for the right error flags. (But, convention is certainly a factor, so if you're working with an existing code base which uses the null object pattern, it might be best to continue.)

Here's some good additional reading about exceptions vs. error variables: Are error variables an anti-pattern or good design?

  • Thanks for the link and the extra pointer on the null object. I was also worried that sometimes it might be better to have an immediate exception thrown, rather than silently working with the null object, although I suppose I could have done some logging... – R. Peereboom Jul 10 '14 at 17:06
0

You could always create a custom exception if you dont find the exceptions you have at your disposal fit correctly.

class MyUsefulException < Exception
end

raise MyUsefulException, 'Huzzah, my exception lives!!!'
  • Custom errors should derive from StandardError or something derived from that. Exception is a low level class that user code should not directly inherit. – thomthom Dec 9 '16 at 12:00
  • @thomthom that was more just psuedo-code placeholder, where Exception could be any of the classes in the Exception Hierarchy tree. I am in agreement with you that you should inherit from StandardError in most cases. – Sean Dec 9 '16 at 18:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.