List of Phobos functions that allocate memory?

Jonathan M Davis jmdavisProg at gmx.com
Fri Feb 7 12:38:59 PST 2014


On Friday, February 07, 2014 14:26:47 Marc Schütz" 
<schuetzm at gmx.net>@puremagic.com wrote:
> On Thursday, 6 February 2014 at 22:15:11 UTC, Brad Anderson wrote:
> > Personally I don't think bad user input qualifies as an
> > exceptional case because it's expected to happen and the
> > program is expected to handle it (and let the user know) when
> > it does. That's just a matter of taste though.
> 
> Hmm... then what _does_ qualify as exceptional in your opinion?

Honestly, I think that the typical approach of discussing exceptions as being 
for "exceptional" circumstances is bad. It inevitably leads to confusion and 
debate over what "exceptional" means. Some programmers would consider that to 
mean any bad input, whereas others would take it to the extreme that they 
should only happen when your program is in an invalid state (essentially what 
we use Errors for). I've found rather that when discussing exceptions it works 
much better to explain exactly why you'd use them, and I think that that comes 
primarily down to three types of circumstances.

1. Code which which should succeed most of the time and which would be far 
cleaner if it's written to throw exceptions - particularly when the 
alternative would be to check error codes on every function call (which would 
be incredibly error-prone). A prime example of this would be a parser. It's 
far cleaner to write a parser which assumes that each step succeeds than it is 
to constantly check that each one succeeded. It makes it so that only code 
that could actually encounter an error has to check for it and so that it can 
easily and cleanly propagate the error to the top. Doing that with error codes 
would generally be a mess, and unless failure is the norm, efficiency 
shouldn't be a problem.

2. Code which you can't actually guarantee will ever succeed. There are some 
cases where you can avoid errors by doing validation before proceeding (e.g. 
testing strings for Unicode correctness before doing a lot of string 
processing), but there are others where you either can't validate ahead of 
time or where you could still end up with an error in spite of your 
validation. A prime example of this would be operating on files. For, 
instance, std.file.isDir will tell you whether a particular file is directory 
or not by returning bool. If that file does not actually exist, then what is 
isDir supposed to do? All it can do is throw an exception, unless you want to 
have a separate out parameter to report whether it succeeded or not or change 
it so that it returns an error code and returns the bool as out parameter, 
both of which would make it much uglier to use. And isDir can't assert that 
the file exists, because that's a runtime condition that cannot be fully 
verified ahead of time. You can (and should) check whether the file exists 
first

if(file.exists)
{
 if(file.isDir)
 {}
 else if(file.isFile)
 {}
 else
 {}
}

but the file system could actually delete that file right out from under you 
between the call to exists and the call to isDir (or between the calls to 
isDir and isFile), so validation reduces how often you hit the error case but 
cannot eliminate it. It should also be rare that isDir will fail (since you 
should be checking that the file exists first). So, throwing an exception 
makes perfect sense. You get clean code that's still able to handle error 
cases rather than them being ignored (as frequently happens with error codes).

3. Code which should succeed most of the time but where doing validation 
essentially requires doing what you're validating for anyway. Again, parsers 
are a good example of this. For instance, to validate that 
"2013-12-22T01:22:27z" is in the valid ISO extended string format for a 
timestamp, you have to do pretty much exactly the same work that you have to 
do to parse out all of the values to convert it to something other than a 
string (e.g. SysTime). So, if you validated it first, you'd be doing the work 
twice. As such, why validate first? Just have it throw an exception when the 
parsing fails. And if for some reason, you expect that there's a high chance 
that the parsing would fail, then you can have a function which returns an 
error code and passed out the result as an out parameter instead, but that 
makes the code much uglier and error-prone. So, in most cases, you'd want it 
to throw an exception on failure. But regardless, you wouldn't want to 
validate it first as that would just be expensive all the time rather than 
more expensive in the (hopefully) rare error case.


The areas that you want to normally avoid exceptions are when you're 
validating up front or when the error condition is likely. If you're 
validating, you're normally asking a question - is this data valid - in which 
case, returning bool is the correct thing to do, not throwing on failure 
(though if the result is false, the caller could choose to throw if 
appropriate). And trying to do something which has a good chance of failing 
should probably return whether it succeeded or not, because you don't want 
exceptions to be your normal code path.

Also, performance-critical stuff may need to go the error-code path rather 
than exceptions simply due to it being performance-critical, but in general, 
error conditions which aren't bugs in your program should be reported via 
exceptions (not error codes) with validation being used where appropriate to 
make it so that the error conditions are infrequent.

- Jonathan M Davis


More information about the Digitalmars-d mailing list