IWETHEY v. 0.3.0 | TODO
1,095 registered users | 0 active users | 0 LpH | Statistics
Login | Create New User
IWETHEY Banner

Welcome to IWETHEY!

New Re: Question about exceptions
My approach to exceptions and error handling is rather binary: Either a function accomplishes its expected duty and returns without error, or it is unable to complete its duty and must signal an error somehow.

[Note: For those familiar with DbC, "unable to complete its duty" equates to not meeting its postconditions.]

That rule makes error handling easy. If the called function that failed is critical for the current function, then the error must be propagated. If the failure of the called function is not critical to my current function, then I can ignore or log the error, and otherwise continue on the current job.

There are lots of ways to signal errors: exceptions, return values, etc. Pick one way and use it consistently. I like exceptions when they are available, for reasons mentioned elsewhere in this thread.

Someone mentioned using exceptions for critical errors and error return values for non-critical. That way lies madness. If an error occurs that prevents a function from completing, then it is critical and must be reported. Whether that reported error is critical in the context of the calling fuction is not the responsibility of the function reporting the error.

Well, that's my 2 cents.
--
-- Jim Weirich jim@weirichhouse.org [link|http://onestepback.org|http://onestepback.org]
---------------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
New Nice point about responsibility, but grey areas abound
Now that more languages support exceptions, we're getting into grey areas regarding "what is an exception", and what does it mean to "prevent a function from completing". Take finding a char in a string: position = find('z', 'banana'). Should the find() function raise an exception, or return, say, -1? The function "completed normally", we just fell through. However, the intent of the function is to return a position--no position is exceptional. So many languages have considered "return -1" to be "completing normally", that's it's hard to break tradition. In langs with DbC constructs, it's easier to nail down, as you say. Those without it are thrashing back and forth over this.
New Re: Nice point about responsibility, but grey areas abound
we're getting into grey areas regarding "what is an exception"

I think you mean "What is an error?" ... we know what exceptions are.

Take finding a char in a string: position = find('z', 'banana'). Should the find() function raise an exception, or return, say, -1?

"Should" is a tough word. That implies one of the choices is correct and the other is incorrect.

I suggest that either answer could perfectly correct given the right circumstances. The difference between the two choices are the difference in the ir post conditions.

The "throw an exception" version has the following contract... (written in whatever little Eiffel I remember)
\n  find(pattern, target: STRING): INTEGER is\n  ensure\n     target[Result] = pattern\n  end\n
This function always returns an index that is can be applied to the target string. And when it does so, the value returned will be the pattern character. Always. The client code can depend on it.

If it cannot, then it must signal the error by throwing an exception.

The "return -1" version uses this contract...
\n  find(pattern, target: STRING): INTEGER is\n  ensure\n    found: not member(pattern, target) implies (Result = -1) \n    not_found: member(pattern, target) implies (target[Result] = pattern)\n  end\n
Notice that the post condition is much more complex for this version. This means that every caller must deal with the extra complexity (i.e. by explicitly checking for -1). But if the not found condition is common enough, this might still be the better choice.

The rule of thumb does tell you what should be errors, it tells you how to treat what you decide are errors.

--
-- Jim Weirich jim@weirichhouse.org [link|http://onestepback.org|http://onestepback.org]
---------------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
New No, we don't
I think you mean "What is an error?" ... we know what exceptions are.
Actualy, that was the question I started this with. What's the difference between an error and an exception?

Any function can return a result, return an error, or throw an exception. If it can't produce a result, is that an error or an exception? Does it depend on whether it was a pre- or post-condition? What's the distinction?


Okay, I can think of a distinction. If it fails a pre-condition, ie: the parameters are not of the right type, it's definitely an exception. Beyond that ... ?
===

Purveyor of Doc Hope's [link|http://DocHope.com|fresh-baked dog biscuits and pet treats].
[link|http://DocHope.com|http://DocHope.com]
Expand Edited by drewk March 17, 2005, 05:25:32 PM EST
New The difference is simple
Exceptions are a mechanism within the language which is supposed to be used to handle errors. Errors are cases of things going wrong. When you encounter an error, you can try to deal with it yourself, throw an exception, or return a value indicating that there is an error.

There is no ambiguity about what an exception is, it is a specific language construct. You either throw it or not.


There is a lot of ambiguity in figuring out whether something is really wrong. That's fully as hard as figuring out what it means for things to be OK.

As for figuring out whether to throw an exception or return an error, Jim's strategy is to either always throw an exception or always return an error - never mix and match. I'd agree with this philosophy. If there is doubt about whose job it is to handle errors, then errors are likely to get dropped on the floor.

Cheers,
Ben
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
New Problem with that
"It's not an error. It's just a null response, meaning it didn't find anything." I hear it already.
===

Purveyor of Doc Hope's [link|http://DocHope.com|fresh-baked dog biscuits and pet treats].
[link|http://DocHope.com|http://DocHope.com]
New See? Whether it is an error IS ambiguous!
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
New I think I know what to do then
My first instinct was to say you return errors or throw exceptions, but not both. I wasn't able to articulate a good reason for it though. But your formulation works for me: An exception is a language-specific mechanism for handling errors. If I start from that, there isn't any reason to use both interchangeably.
===

Purveyor of Doc Hope's [link|http://DocHope.com|fresh-baked dog biscuits and pet treats].
[link|http://DocHope.com|http://DocHope.com]
New Exactly
I have come to believe that idealism without discipline is a quick road to disaster, while discipline without idealism is pointless. -- Aaron Ward (my brother)
New Re: Problem with that
"It's not an error. It's just a null response, meaning it didn't find anything."

If its not an error, then don't throw and exception. If it is an error, then do throw an exception.

You can't decide if something is an error until you know the purpose of the function you are writing. If the purpose is "Find the index", then not finding is an error. If the purpose is "Find the index if it exists", then not finding it is not an error.

Both choices make sense. Pick the one that makes sense to you at this moment. If you pick wrong, then let me tell you about a little thing called refactoring.

I remember working on a library that had open and close methods. I decided to make it an error to close an already closed connection (i.e. the purpose was "Close an open connection"). After writing some code using it, I discovered that it complicated my client logic testing to see if something was really open before attempting to close it. I changed the function to mean "Make sure the connection is closed", and the client code got significantly simpler.

--
-- Jim Weirich jim@weirichhouse.org [link|http://onestepback.org|http://onestepback.org]
---------------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
New Thats the sort of logic that makes me wary of exceptions.
Wary of exceptions as they are usually implemented, that is.

I like the failure model that SNOBOL and Icon use. They're a bit like miniature exceptions: if some function or operator doesn't have a value to return, it fails. Failure simply means "it didn't work". Catching it can be done explicitly with constructs like if and while, or implicitly which produces back-tracking and goal-directed evaluation (this should be familiar to RE wizards). If it isn't handled, it propagates upwards until it is or it can't go up anymore (letting something fail for the side-effects is a known programming technique in Icon). It removes the problem of "handling it elsewhere" that try/catch can produce.

OTOH, exceptions have some features that failure doesn't. The obvious one is that different types of exceptions can be raised. Failure is just failure. There are some system functions that have to fail when there's a problem; but you have to call another function to see how and why they failed.

(A less-obvious feature of exceptions is that they have much larger scope than failure. In Icon, failure is often bounded, so that a statement with an uncaught failure doesn't cause the language to backtrack farther than it should. This is by design. Exceptions have to play games with the stack as they propagate up until something catches them.)

Whether something is an error or not in a failure model is somewhat easier to answer: is there a value to return? No? Okay, fail*. As far as I can tell from this discussion, exceptions are *just* unwieldy enough that it actually becomes an issue as to whether a function, faced with a problem, should say "that's an error - throw an exception" or "no, that's not really an error - no exception needed." :-) Ouch.

Wade.

* To be fair, even Icon doesn't follow this slavishly. There are some - mainly graphcis - functions which return &null for one condition and "" for its opposite. It turns out that in actual usage, this is more versatile, particularly as there are operators to quickly and directly turn &null or not-&null into failure.

Is it enough to love
Is it enough to breathe
Somebody rip my heart out
And leave me here to bleed
 
Is it enough to die
Somebody save my life
I'd rather be Anything but Ordinary
Please

-- "Anything but Ordinary" by Avril Lavigne.

New Exceptions are one form of Continuation
Icon's Generators are another form. And while we're tossing around various ways to cope with what amounts to problems in program continuity (errors, exceptions, whatever), I should also mention another way that's used to handle errors. Instead of using a setjmp/longjmp type mechanism of throwing/catching exceptions, why not just send a block of code that tells the function what to do in case of error? Of course, this requires lambdas or block closures. But it sends the code down into the place where the exception is easiest to handle (i.e. it is more specific). An example of this would be something akin to Smalltalk's onUnWind: type parameters.
New Icon's generators rely on the failure model.
That's how you get back-tracking. :-)

Wade.

Is it enough to love
Is it enough to breathe
Somebody rip my heart out
And leave me here to bleed
 
Is it enough to die
Somebody save my life
I'd rather be Anything but Ordinary
Please

-- "Anything but Ordinary" by Avril Lavigne.

New Disabling assertions
Factored into the mix is the question of performance. Raising exceptions can be an expensive proposition, such that exceptions might ought to be raised only in exceptional circumstances - i.e. those errors which are not part of the normal flow or behavior of the program.

One other factor in the DbC mode of operation is that a lot of people seemed to have disabled the assertions in the production compilation - for reasons of speed. Using an assertion scheme to raise exceptions is fine as long as you don't just use the contracts during the testing phase.
New That's one of the points he raised
Raising exceptions can be an expensive proposition, such that exceptions might ought to be raised only in exceptional circumstances
That's almost word-for-word what he said. He also said that each exception gets pushed onto the stack, which is more expensive than keeping it in memory. I'm not clear on how that's different.

But even if it is more computationally intensive, I think coding to that standard is premature optimization. I think code should be written to be understandable and maintainable until after a bottleneck has been identified. PHP doesn't do checked exceptions, so all you have to do is throw exceptions and catch them where you can handle them. Each function can decide what counts as an exception and each place calling it can decide how critical it is in that context.

So, how much more "expensive" is it to use exceptions rather than returning error objects?
===

Purveyor of Doc Hope's [link|http://DocHope.com|fresh-baked dog biscuits and pet treats].
[link|http://DocHope.com|http://DocHope.com]
New Expense is relative
In some cases it might be considered premature optimization, but in those cases where you know the error is (a) normal; (b) frequent; and (c) numerous, then you would want to factor that knowledge into the design. As for why it is expensive, throwing (raising) an error results in an allocation of the Error object with the stack information (used for debugging or catching an exception). Can't recall the numbers for Java but there has been some quantification of the relative speeds of using throw versus returning a result back that captures that an error occurred.

I also might note that there are other ways that libraries handle errors. Typical in floating point operations is to send a NaN (not-a-number) back as the result. The FFPs have a special encoding for this number. A function which returns a list might also return an empty list to indicate no matches. But these are all just variations on manipulating the return result so that errors are encoded within the return value.

Another method to deal with errors has to do with pre- and post-functions that tell you whether an error will occur or has occurred. For example, before you open a file for a read operation, you might want to check if the file exists. The open file operation might throw an exception if the file does not exist, but if you check first, you can avoid that error in the first place. Along similar lines, but less palatable is to have a function which verifies that no error occurs. For example, you might open the file but no error is signaled by an exception or the returned value. Instead, you could call an isOk function after you attempted the file read.

So tell you buddy to make sure to have these extra error handling mechanisms in place to allow the end user to decide how they want to handle the error. Better yet, allow the user to set a property in the object to indicate how they want to handle the errors (ErrorException, ErrorReturnValue, ErrorPreCheck, ErrorPostCheck, etc...).
New Re: That's one of the points he raised
So, how much more "expensive" is it to use exceptions rather than returning error objects?

I've seen a performance test that says that throwing an exception is about twice as expensive as returning an error in PHP. But in either case the cost of the error is trivial compared to the time spent running a script.

The cost does vary a lot by language, in some languages throwing an exception can be an order of magnitude more expensive then returning an error.

Jay
New DbC?
===

Purveyor of Doc Hope's [link|http://DocHope.com|fresh-baked dog biscuits and pet treats].
[link|http://DocHope.com|http://DocHope.com]
New Design by Contract
In Java, that's done via interfaces, for example.
-YendorMike

"They that can give up essential liberty to obtain a little temporary safety deserve neither liberty nor safety."
- Benjamin Franklin, 1759 Historical Review of Pennsylvania
New Not the same thing.
DbC is an Eiffel term. Each method has pre and post conditions that must be satisfied (the contract), much like built-in assertions. The contracts can be used for things like proscribing side-effects, etc.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New That's not strictly Eiffel;
They're certainly teaching that to us in my degree in a plethora of our courses, like software specs, application design, etc.
--\n-------------------------------------------------------------------\n* Jack Troughton                            jake at consultron.ca *\n* [link|http://consultron.ca|http://consultron.ca]                   [link|irc://irc.ecomstation.ca|irc://irc.ecomstation.ca] *\n* Kingston Ontario Canada               [link|news://news.consultron.ca|news://news.consultron.ca] *\n-------------------------------------------------------------------
New It's built into Eiffel
You can simulate it in Java with AOP, though.
Regards,

-scott anderson

"Welcome to Rivendell, Mr. Anderson..."
New It is DESIGN by Contract after all
That's not strictly Eiffel;

Of course not. I don't think the concept is even original to Eiffel, but Bertrand Meyer certainly took the ideas then refined and developed them. The term "Design by Contract" is coined by Meyer and the Eiffel language is probably the best concrete implementation of DbC in a programming language.

However, it is DESIGN by Contract, not CODE by Contract. That's a clue that the concepts apply to something broader than a just a programming language. In fact, it is quite possible to design a system using DbC without ever having direct language support for DbC.
--
-- Jim Weirich jim@weirichhouse.org [link|http://onestepback.org|http://onestepback.org]
---------------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct,
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)
New As you say
the fact that you don't need specific language support to use the concept when designing an app is sorta my point.

It is a very useful design concept, no matter what language you use.
--\n-------------------------------------------------------------------\n* Jack Troughton                            jake at consultron.ca *\n* [link|http://consultron.ca|http://consultron.ca]                   [link|irc://irc.ecomstation.ca|irc://irc.ecomstation.ca] *\n* Kingston Ontario Canada               [link|news://news.consultron.ca|news://news.consultron.ca] *\n-------------------------------------------------------------------
     Question about exceptions - (drewk) - (31)
         Lots of discussions about that - (FuManChu) - (6)
             That only goes for one kind of exceptions! - (CRConrad) - (1)
                 What does the "checked" mean to you? - (FuManChu)
             But he's saying that you should use both - (drewk) - (3)
                 My rule of thumb is, - (Arkadiy)
                 Pick one and stick with it. - (admin)
                 You can do both (or more accurately: either) with or without - (FuManChu)
         Re: Question about exceptions - (JimWeirich) - (23)
             Nice point about responsibility, but grey areas abound - (FuManChu) - (11)
                 Re: Nice point about responsibility, but grey areas abound - (JimWeirich) - (10)
                     No, we don't - (drewk) - (9)
                         The difference is simple - (ben_tilly) - (8)
                             Problem with that - (drewk) - (4)
                                 See? Whether it is an error IS ambiguous! -NT - (ben_tilly) - (2)
                                     I think I know what to do then - (drewk) - (1)
                                         Exactly -NT - (ben_tilly)
                                 Re: Problem with that - (JimWeirich)
                             Thats the sort of logic that makes me wary of exceptions. - (static) - (2)
                                 Exceptions are one form of Continuation - (ChrisR) - (1)
                                     Icon's generators rely on the failure model. - (static)
             Disabling assertions - (ChrisR) - (3)
                 That's one of the points he raised - (drewk) - (2)
                     Expense is relative - (ChrisR)
                     Re: That's one of the points he raised - (JayMehaffey)
             DbC? -NT - (drewk) - (6)
                 Design by Contract - (Yendor) - (5)
                     Not the same thing. - (admin) - (4)
                         That's not strictly Eiffel; - (jake123) - (3)
                             It's built into Eiffel - (admin)
                             It is DESIGN by Contract after all - (JimWeirich) - (1)
                                 As you say - (jake123)

Son, when you've lived as long as I have, you'll want to forget most of it too.
181 ms