On 2013-11-18 08:28, Jonathan M Davis wrote:

That code's like that just because I like to put empty lines before and after
if statements and before return statements, as I think that that improves
legibility. Short functions like that suffer as a result, because they end up
with a larger proportion of the lines being empty than is normal. I'm always a
bit torn on that, because I don't like having quite that many empty lines in
so few lines, but I also don't like not having space around if statements and
return statements. I never feel like I can find a nice, legible balance with
short functions like that.

I like the empty newlines as well. Otherwise it feels like reading a text without paragraphs.

Fine with me. I might still favor the try-catch in cases where you can clearly
wrap it around one function call, because then you avoid problems where you've
accidentally effectively marked the whole function as trusted-nothrow when you
only want to mark one function call that way. But you could do the same thing
with scope(failure) and a new scope. The main problem is when you can't really
put the calls that need to be trusted-nothrow inside a new scope, in which
case, you're forced to mark the whole function (or at least large portions of
it) as trusted-nothrow by wrapping it all in a try-catch or scope(failure).

In this case the whole function is wrapped on a try-block. In those cases I think a scope(failure) looks nicer.

2. Relax the nothrow guarantees. After all, nothrow is opt-in.

I'm not quite sure what you're suggesting here. Make it so that nothrow does
checking at runtime instead of compile time? That would be moving in the
direction of C++ and throw specifiers (or more precisely, noexcept, I suppose).
If that's what you're suggesting, I'd be very much against that. I think that
the fact D's nothrow is statically checked is a huge advantage over C++'s
noexcept. The fact that you have to sometimes use try-catch blocks (or
scope(failure) if that works) to make it work is essentially the same as
needing @trusted to make some stuff @safe. I wouldn't want to throw away
@trusted in favor of making @safe more lax either (though that's almost all
static checking which can't be done at runtime, unlike with noexcept).

Of course, there's no way to verify trusted-nothrow except at runtime like
std.datetime is doing with try-catch and assertions, but most code _can_ be
checked statically (including the code that calls the functions that use the
try-catch-assert idiom to be able to be nothrow), and that's much more
pleasant, particularly because it's actually checked by the compiler that way
rather than just blowing up on you at runtime.

I suppose that if it were considered annoying enough to have to use try-catch
blocks or scope(failure), we could add a nothrow equivalent to @trusted to
mark functions with, though it's already been argued that @trusted should be
on pieces of a function rather than on the whole function, and it would
arguably be better to mark sections of a function as trusted-nothrow rather
than the entire thing. try-catch lets us do that already, but it might be nice
to be able to do the equivalent of

      @property FracSec fracSec() const nothrow
      {
          trusted-nothrow
          {
              auto hnsecs = removeUnitsFromHNSecs!"days"(adjTime);

              if(hnsecs < 0)
                  hnsecs += convert!("hours", "hnsecs")(24);

              hnsecs = removeUnitsFromHNSecs!"seconds"(hnsecs);

              return FracSec.from!"hnsecs"(cast(int)hnsecs);
          }
      }

and have the compiler insert the catch and assertion for you.

Just do something like this:

void trusted_nothrow (alias block) ()
{
    scope(failure) assert(0);
    block();
}

trusted_nothrow!({
    // code
});

Not as pretty. Yet another prefect example for AST macros :)

--
/Jacob Carlborg

Reply via email to