try/catch idiom in std.datetime
Andrei Alexandrescu
SeeWebsiteForEmail at erdani.org
Sun Nov 17 22:32:46 PST 2013
I'm of a stance that good code should have many throws and few try/catch
statements. I was curious how Phobos does there, so I ran a few simple
greps around.
Seems like there's about 145 try statements in Phobos. Of these, more
than a third (51) belong to std.datetime.
Looks like the following idiom is often present in std.datetime:
@property FracSec fracSec() const nothrow
{
try
{
auto hnsecs = removeUnitsFromHNSecs!"days"(adjTime);
if(hnsecs < 0)
hnsecs += convert!("hours", "hnsecs")(24);
hnsecs = removeUnitsFromHNSecs!"seconds"(hnsecs);
return FracSec.from!"hnsecs"(cast(int)hnsecs);
}
catch(Exception e)
assert(0, "FracSec.from!\"hnsecs\"() threw.");
}
(It may seem I chose this example to discuss the "let's insert one empty
line every other line" idiom. I didn't.) Essentially the code relies on
calls that may generally throw, but calls them with parameters that
should guarantee there won't be any throwing. In wanting to offer as
many "nothrow" guarantees as possible, the code ends up inserting these
try/catch statements - seemingly needlessly.
This is quite heavy-handed, so I was wondering what we could do to
improve on this. I thought of the following possibility:
@property FracSec fracSec() const nothrow
{
scope(failure) assert(0, "FracSec.from!\"hnsecs\"() threw.");
auto hnsecs = removeUnitsFromHNSecs!"days"(adjTime);
if (hnsecs < 0)
hnsecs += convert!("hours", "hnsecs")(24);
hnsecs = removeUnitsFromHNSecs!"seconds"(hnsecs);
return FracSec.from!"hnsecs"(cast(int)hnsecs);
}
This at least leaves the normal path unaltered and deals with the
unexpected in a more isolated manner. I was pleased that the changed
code compiled just fine. My happiness was short-lived because before
long I figured this compiles as well:
...
scope(failure) {}
...
So it's not that the compiler cleverly figured the function will not
throw. Instead, the compiler considers everything dandy as soon as it
sees a scope(failure), no matter of the statement it controls. I'll
report that bug soon.
What would be the best approach here?
0. Do nothing. This is as good as it gets.
1. Fix scope(failure) and then use it.
2. Relax the nothrow guarantees. After all, nothrow is opt-in.
3. Look into API changes that add nothrow, narrower functions to the
more general ones that may throw.
4. ...?
Andrei
More information about the Digitalmars-d
mailing list