Jump to page: 1 2
Thread overview
Contracts or Exceptions?
Mar 29, 2011
Mike Linford
Mar 29, 2011
spir
Mar 29, 2011
Kai Meyer
Mar 30, 2011
Ali Çehreli
Mar 30, 2011
spir
Mar 30, 2011
Kai Meyer
Mar 30, 2011
Ali Çehreli
Mar 30, 2011
Jonathan M Davis
Mar 30, 2011
Ali Çehreli
Mar 30, 2011
Jonathan M Davis
Mar 30, 2011
bearophile
Mar 30, 2011
Kagamin
Mar 30, 2011
Kai Meyer
Mar 31, 2011
Kagamin
Mar 30, 2011
Mike Linford
Mar 30, 2011
Kagamin
March 29, 2011
Hello,

So I'm writing a function for a library. It takes a struct as an argument. The struct's fields can't just be any old values, though. The function won't work if some of the fields are weird. It could return an erroneous value, or even crash.

The thing is, though, that I can't tell whether the best approach is to use an in-contract or throw an exception if it doesn't pass my test. What would you guys recommend?



-- 
--Mike Linford
March 29, 2011
On Tue, 29 Mar 2011 14:40:02 -0400, Mike Linford <mike.linford.reg@gmail.com> wrote:

> Hello,
>
> So I'm writing a function for a library. It takes a struct as an
> argument. The struct's fields can't just be any old values, though. The
> function won't work if some of the fields are weird. It could return an
> erroneous value, or even crash.
>
> The thing is, though, that I can't tell whether the best approach is to
> use an in-contract or throw an exception if it doesn't pass my test. What
> would you guys recommend?

This has been discussed very recently on the main newsgroup (digitalmars.D).  It is not an easy question to answer.

There are two ways to answer it easily:  1. if the input to the function will always be deterministic, meaning there is no chance some environmental cause can affect the input, or the validity of the input, then use contracts, this should catch any code errors during testing.  2. if the input to the function will always be generated external to the program (i.e. from a file), then you should use exceptions.

If it could be either, there are different schools of thought on this.  If the function isn't performance critical, throwing an exception is likely a good choice.  However, if it is performance critical, I'd recommend using contracts.  Then if you have a situation when your input is externally generated, you need to check it outside the function with an exception thrown on error.

-Steve
March 29, 2011
On 03/29/2011 08:49 PM, Steven Schveighoffer wrote:
> On Tue, 29 Mar 2011 14:40:02 -0400, Mike Linford <mike.linford.reg@gmail.com>
> wrote:
>
>> Hello,
>>
>> So I'm writing a function for a library. It takes a struct as an
>> argument. The struct's fields can't just be any old values, though. The
>> function won't work if some of the fields are weird. It could return an
>> erroneous value, or even crash.
>>
>> The thing is, though, that I can't tell whether the best approach is to
>> use an in-contract or throw an exception if it doesn't pass my test. What
>> would you guys recommend?
>
> This has been discussed very recently on the main newsgroup (digitalmars.D). It
> is not an easy question to answer.
>
> There are two ways to answer it easily: 1. if the input to the function will
> always be deterministic, meaning there is no chance some environmental cause
> can affect the input, or the validity of the input, then use contracts, this
> should catch any code errors during testing. 2. if the input to the function
> will always be generated external to the program (i.e. from a file), then you
> should use exceptions.
>
> If it could be either, there are different schools of thought on this. If the
> function isn't performance critical, throwing an exception is likely a good
> choice. However, if it is performance critical, I'd recommend using contracts.
> Then if you have a situation when your input is externally generated, you need
> to check it outside the function with an exception thrown on error.

... or users of your service should be warned it is their reponsability to check validity of inputs to it (case of a lib).

Denis
-- 
_________________
vita es estrany
spir.wikidot.com

March 29, 2011
On 03/29/2011 12:40 PM, Mike Linford wrote:
> Hello,
>
> So I'm writing a function for a library. It takes a struct as an
> argument. The struct's fields can't just be any old values, though. The
> function won't work if some of the fields are weird. It could return an
> erroneous value, or even crash.
>
> The thing is, though, that I can't tell whether the best approach is to
> use an in-contract or throw an exception if it doesn't pass my test. What
> would you guys recommend?
>
>
>

I was given two words of advice on exceptions:
"Use exceptions for the exceptional"
"Use exceptions only for the exceptional"

Meaning, if you expect something to fail frequently, using a try/catch is much more expensive than an if/else. "The exceptional" is something that should rarely ever occur, like running out of memory.

For contracts, they are usually meant as a developer tool to warn them when that they will be in no-man's land if they attempt to proceed any further. They are, therefore, not compiled in when you pass the D compiler the -release flag.

I don't think that contracts and exceptions are mutually exclusive. They provide two different safeguards. One is a tool to aid in the development process, one is a tool to safeguard against exceptional run-time scenarios.

However, I think if I rephrase your question a little bit, it might provide you what I think you're after. I'm making an assumption here, so I may be way off the mark.

"Who's responsibility is it to check whether or not the data passed into the function is valid? Should I accept whatever the user wants to pass in, and let them know when it's invalid, or should I trust that the user is sending in good data?"

I think that's a choice for you to make. Contract programming is often used to put the burden of validation on the user of the library (meaning programmer writing software taht uses your library). Exceptions could be used to indicate that the library writer is accepting responsibility for validating the data before using it.

But validating data is not the only reason to use exceptions, and it's not unusual for a library to skip all validations and force the user to do all the checking before hand. Arrays are a good example. When not in -release mode, array boundaries are checked upon every access to the array, and an exception is thrown if access goes out of bounds. In -release mode, if you go out of bounds you get a segfault. This is one example of giving the user (programmer) of arrays the responsibility to check boundaries so that the library can focus on being fast.

I think the choice comes down to a balance between performance, responsibility, and maintainability. (Oh, and you'll usually get it wrong the first time, so don't be sad.)
March 30, 2011
Thanks for the responses, everybody. They were helpful :-)

-- 
--Mike Linford
March 30, 2011
On 03/29/2011 03:40 PM, Kai Meyer wrote:

> I was given two words of advice on exceptions:
> "Use exceptions for the exceptional"
> "Use exceptions only for the exceptional"

Those advices are given by wise people: they are wise only because they leave the definition as vague as "exceptional." :)

And what do we do for the "not so exceptional"? Do we return error codes? So the function implementation will be complicated and the caller code will be complicated.

Exceptions are a great tool to eliminate the need for error codes.

Here is what I follow:

- Functions have specific tasks to do; if those tasks cannot be accomplished, the function must throw.

In some cases the function can continue, but that behavior must be documented. For example, if an HTML library function is responsible for making HTML headers, of which only the levels in the range of 1-6 are valid, that function may throw when the level is outside of the valid range, for in that case it cannot "make an HTML header"; or it can document that if the level is outside of the range, 1 or 6 will be used.

- Catch exceptions only when there is a sensible thing to do at that level: log an error, skip that operation, go back to the user with an error code, take corrective action, etc.

Disclaimer: That is what I follow in C++ code. I don't have experience with exception safety in D. I don't know issues that may be specific to D.

Ali

March 30, 2011
On 03/30/2011 05:32 AM, Ali Çehreli wrote:
> On 03/29/2011 03:40 PM, Kai Meyer wrote:
>
>>  I was given two words of advice on exceptions:
>>  "Use exceptions for the exceptional"
>>  "Use exceptions only for the exceptional"
>
> Those advices are given by wise people: they are wise only because they leave
> the definition as vague as "exceptional." :)
>
> And what do we do for the "not so exceptional"? Do we return error codes? So
> the function implementation will be complicated and the caller code will be
> complicated.
>
> Exceptions are a great tool to eliminate the need for error codes.
>
> Here is what I follow:
>
> - Functions have specific tasks to do; if those tasks cannot be accomplished,
> the function must throw.
>
> In some cases the function can continue, but that behavior must be documented.
> For example, if an HTML library function is responsible for making HTML
> headers, of which only the levels in the range of 1-6 are valid, that function
> may throw when the level is outside of the valid range, for in that case it
> cannot "make an HTML header"; or it can document that if the level is outside
> of the range, 1 or 6 will be used.
>
> - Catch exceptions only when there is a sensible thing to do at that level: log
> an error, skip that operation, go back to the user with an error code, take
> corrective action, etc.
>
> Disclaimer: That is what I follow in C++ code. I don't have experience with
> exception safety in D. I don't know issues that may be specific to D.

These are sensible and well expressed guidelines, thank you.
In other languages, I happened to use exceptions as a // channel for side-information (eg 'nomatch' for a matching func), but in D I realised how 'exceptionnally' (!) costly throwing & catching exceptions is, so that I do not do it anymore. No idea though whether this exceptional cost is perticular to D.

Denis
-- 
_________________
vita es estrany
spir.wikidot.com

March 30, 2011
Mike Linford Wrote:

> Hello,
> 
> So I'm writing a function for a library. It takes a struct as an argument. The struct's fields can't just be any old values, though. The function won't work if some of the fields are weird. It could return an erroneous value, or even crash.
> 
> The thing is, though, that I can't tell whether the best approach is to use an in-contract or throw an exception if it doesn't pass my test. What would you guys recommend?

Error (like AssertError) is intended to be irrecoverable like out of memory or stack overflow, Exception is intended to be catchable.
March 30, 2011
Kai Meyer Wrote:

> do all the checking before hand. Arrays are a good example. When not in -release mode, array boundaries are checked upon every access to the array, and an exception is thrown if access goes out of bounds. In -release mode, if you go out of bounds you get a segfault.

No, you get a remote root vulnerability.
March 30, 2011
On 03/30/2011 08:25 AM, Kagamin wrote:
> Kai Meyer Wrote:
>
>> do all the checking before hand. Arrays are a good example. When not in
>> -release mode, array boundaries are checked upon every access to the
>> array, and an exception is thrown if access goes out of bounds. In
>> -release mode, if you go out of bounds you get a segfault.
>
> No, you get a remote root vulnerability.

Sure, but the point is that arrays can be used in a way that performs as fast as possible, therefore it becomes the programmer's job to ensure that all access to the array is within bounds, which is faster than making the array check itself every time.
« First   ‹ Prev
1 2