views:

103

answers:

5

When I design a class I often have trouble deciding if I should throw an exception or have 2 func with the 2nd returning an err value. In the case of 2 functions how should I name the exception and non exception method?

For example if I wrote a class that decompresses a stream and the stream had errors or incomplete I would throw an exception. However what if the app is trying to recover data from the stream and excepts an error? It would want a return value instead? So how should I name the 2nd function?

Or should I not have both an exception method and a nonexception method?

+2  A: 

Or should I not have both an exception method and a nonexception method?

That. Unless you really have time to burn maintaining two separate but mostly-identical methods.

If you really need to allow for clients that won't consider errors exceptional, then just indicate them with a return value and be done with it... Otherwise, just write the exception-throwing version and let the odd error-eating client handle the exception.

Shog9
I would have the exception throwing call the return val method and NOT have repeat code. But i agree with you. I'll write it to throw an exception then change it to return value if i need to.
acidzombie24
+1  A: 

I believe that you should try to use exceptions even if you're not going to exit program in some cases. You just need to create a specific exception type for your errors. And catch only them when you need to do some spefic logic. All other exceptions will go to upper level of your code. For example you've created function which throws exception on any error. And you don't want to exit program if user specified incorrect file name. Here is how it can look:

## this is top level try/catch block 
try {
    ## your main code is here
    ...
    ## somewhere deep in your code
    try {
        ## we trying to open file specified by user
    }
    catch (FileNotFoundException) {
        ## we are not going to exit on this error
        ## let's just show a user an error message 
        ## and try to ask different file to open
    }

} catch (Exception) {
    ## catch all exceptions here 
    ## the best thing we can do here is save exception to log and quit }
}

We just need to create hierarchy of exceptions (if your language allows it):

Exception <-- MoreSpecificException

This approach is used in Java

Ivan Nevostruev
OTOH, if the code calling these routines will be immediately catching these exceptions *most of the time*, then it's quite a bit more verbose than the equivalent return-value code. And... not really exceptional!
Shog9
You can always make another function which will just convert exception into return code. But it should be done carefull. The biggest problem with error codes is that nobody checks them, and if they are checked you code can became very complicated.
Ivan Nevostruev
The original question is not bound to any specific language. The advice to "you should try to use exceptions even if you're not going to exit program in some cases" is certainly true and appropriate in some languages (Java, C#), but is definitely wrong in others (e.g. Objective-C).
harms
I think the question named "Designing a class with **Exceptions**" doesn't make sense if target language don't have exception support
Ivan Nevostruev
@Ivan: well, if you're providing information the caller *needs* then they can't really ignore it. For instance, in the OP's stream-reading example, a return value could indicate the bytes read: without that, the caller cannot know how much valid data was returned. Contrast that with a routine that throws an exception on EOF: the caller would now be unable to ever use this routine without exception handling in place, even though EOF is hardly exceptional...
Shog9
@Shog9: Design should be based on level of abstration which you need. If you want a low level function that reads chuck of data then you should be ready for all posible exceptional situation. But if you just want to read all text from file. Then your function can return an empty string on "file not found" and you don't know anything about exception. If you try to create a universal function which will be sitable for all situations then it'll be a big one.
Ivan Nevostruev
Uh-huh. That's why i'm arguing for picking *one* technique based on the needs of the calling code. If it needs to continue linear execution in the presence of errors, then exceptions aren't really appropriate (you're effectively converting them to error codes anyway); if not, then they're fine. I'm not sure where you're coming from with the size/complexity concern, given the double-nested exception handler you originally suggested...
Shog9
@Shog9: My personal feeling of 2 designs (exceptions vs return codes): I like exceptions more. May be it's becase I've seen to many bad code using "return codes" paradigm. Which looked really nice after converting to "exception" paradigm.
Ivan Nevostruev
Oh, I agree - exceptions are great, *when they make sense* (non-local error handling). I just don't care for the "wrap function calls in exception handlers" technique - it's essentially the same as return values, but more verbose. The simplest possible solution should be the rule: return values are simpler for local error-handling, but exceptions beat passing return values up the call stack.
Shog9
+2  A: 

It depends on the language, but...

In my opinion, two versions of each potentially failing method imposes too high a cognitive burden on the API user, and too high a burden on the API maintainer. My personal preference is for exceptions, since that's fewer parameters to remember the order of.

Jonathan Feinberg
A: 

I would only throw an exception on the decompression function if the results were not usable. If they were usable, return the results and then the function that reads those results can throw an exception instead. IE

try
{
    results = decompress(file); // only throws exceptions on non-usable files
} catch (FileNotFoundException) {
    // file was not usable, can't recover anything, insert nuclear error handling here
}
try
{
    read(results);
} catch (ErrorThatIsRecoverableException) {
    partialRead(results);
}

so read() is the function you call on normal data, partialRead is the function that handles trying to recover screwed-up-but-still-usable data. And of course, you don't necessarily need exceptions or separate functions at all- you could do the error handling all within the read() function.

Brian Schroth
+1  A: 

Exceptions should normally be used for exceptional conditions, whatever they may be. Being unable to decompress a file is probably an exceptional condition (unless, for example, you're writing a program to scan for badly compressed files). Bad data may or may not be exceptional.

If you've got a class decompressing a stream, then what it should do is decompress the stream, and not try to interpret its contents. Another class should use the first class to get decompressed input, and do the interpretation. That gives you separation of functionality, and good cohesion. Avoid classes where you're tempted to put an "And" in their names: "DecompressAndParseInput" is a bad class name.

Given two classes, there's no particular reason why you have to use the same error-reporting method for both. The decompressor could throw, and the parser could return an error code.

David Thornley