assert(expression, error)

Jonathan M Davis jmdavisProg at gmx.com
Sat Feb 12 08:27:54 PST 2011


On Saturday 12 February 2011 08:05:15 Andrej Mitrovic wrote:
> On 2/12/11, Jonathan M Davis <jmdavisProg at gmx.com> wrote:
> > But
> > if
> > your function isn't likely to be inlined anyway, or for some reason, you
> > just
> > don't like having the if statement, then enforce is just fine.
> > 
> > - Jonathan M Davis
> 
> It's noticeable in code and partially self-documenting, that's why I
> use it. I could go with
> if (exp) throw new exc();
> 
> Same deal, I guess.
> 
> As for inlining, I really have yet to push D to it's limits to see
> that as a problem.

I have a major problem with functions which are _obviously_ inlineable not being 
inlineable just because of using enforce. For instance, take the function on 
std.datetime.TimeOfDay which is used to set the hour. I could write it as

    @property void hour(int hour) pure
    {
        enforce(hour >= 0 && hour < 24,
                     new DateTimeException(numToString(hour) ~ " is not a valid 
hour of the day."));

        _hour = cast(ubyte)hour;
    }

or I could write it

    @property void hour(int hour) pure
    {
        if(hour < 0 || hour >= 24)
            throw new DateTimeException(numToString(hour) ~ " is not a valid 
hour of the day."));

        _hour = cast(ubyte)hour;
    }

Aside from enforce, this function is a one-liner. It's obvious that it should be 
inlined and that it _would_ be inlined if enforce isn't used. But if I were to 
use enforce, it couldn't be inlined. It's situations like that which really 
bother me. enforce is definitely and obviously harming code efficiency in such a 
case.

Now, what happened a lot of the time in std.datetime is that I ended up with a 
helper function with did something similar to enforce (simply because the same 
sort of thing had to be enforced in multiple places, so a helper function made a 
lot of sense), and I didn't make that helper function lazy. For instance, the 
actual definition for the hour property is

    @property void hour(int hour) pure
    {
        enforceValid!"hours"(hour);
        _hour = cast(ubyte)hour;
    }

After all the template fun is sorted out, the enforceValid line should become 
something like

        if(!(hour >= 0 && hour <= TimeOfDay.maxHour))
            throw new DateTimeException(numToString(hour) ~ " is not a valid 
hour of the day.", file, line);

That should be totally inlineable _and_ it has the advantage of not making you 
use an if statement if you want to avoid that. But I'm increasingly finding that 
that is a pattern in my code. I need to validate something multiple times 
throughout my code, and I want it to result in the same exception each time. So, 
I create a helper function which does the test and then throws if it fails. And 
often, I create a separate function which does the test and returns the result 
(making the helper enforce-like function call that function). That way, I can 
use the same test in assertions and the like if need be.

So, if you're testing the same thing in multiple places, you'll probably want to 
write your own helper function anyway, completely obviating enforce. The overall 
result is that I rarely use enforce.

- Jonathan M Davis


More information about the Digitalmars-d-learn mailing list