assert and enforce - D Programming Language

Menu

- Learn
- Documentation
  - Language Reference
  - Library Reference
  - Command-line Reference
  - Feature Overview
  - Articles
- Downloads
- Packages
- Community
  - Blog
  - Orgs using D
  - Twitter
  - Calendar
  - Discord (community-run)
  - Forums
  - IRC
  - Wiki
  - Issues
  - Contributing
  - Contributors
  - Foundation
  - Security Team
  - Donate
  - Sponsors
- Resources
  - Tour
  - Books
  - Tutorials
  - Tools
  - Editors
  - IDEs
  - run.dlang.io
  - Visual D
  - Acknowledgments
  - D Style
  - Glossary
  - Sitemap

Search
Report a bug
If you spot a problem with this page, click here to create a Bugzilla issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

# assert and enforce

In the previous two chapters we have seen how exceptions and `scope` statements are used toward program correctness. `assert` is another powerful tool to achieve the same goal by ensuring that certain assumptions that the program is based on are valid.

It may sometimes be difficult to decide whether to throw an exception or to call `assert`. I will use `assert` in all of the examples below without much justification. I will explain the differences later in the chapter.

Although not always obvious, programs are full of assumptions. For example, the following function is written under the assumption that both age parameters are greater than or equal to zero:

    double averageAge(double first, double second) {
        return (first + second) / 2;
    }

Although it may be invalid for the program to ever have an age value that is negative, the function would still produce an average, which may be used in the program unnoticed, resulting in the program's continuing with incorrect data.

As another example, the following function assumes that it will always be called with two commands: "sing" or "dance":

    void applyCommand(string command) {
        if (command == "sing") {
            robotSing();

        } else {
            robotDance();
        }
    }

Because of that assumption, the `robotDance()` function would be called for every command other than "sing", valid or invalid.

When such assumptions are kept only in the programmer's mind, the program may end up working incorrectly. `assert` statements check assumptions and terminate programs immediately when they are not valid.

##### Syntax

`assert` can be used in two ways:

        assert(logical_expression);
        assert(logical_expression, message);

The logical expression represents an assumption about the program. `assert` evaluates that expression to validate that assumption. If the value of the logical expression is `true` then the assumption is considered to be valid. Otherwise the assumption is invalid and an `AssertError` is thrown.

As its name suggests, this exception is inherited from `Error`, and as you may remember from the Exceptions chapter, exceptions that are inherited from `Error` must never be caught. It is important for the program to be terminated right away instead of continuing under invalid assumptions.

The two implicit assumptions of `averageAge()` above may be spelled out by two `assert` calls as in the following function:

    double averageAge(double first, double second) {
        assert(first >= 0);
        assert(second >= 0);

        return (first + second) / 2;
    }

    void main() {
        auto result = averageAge(-1, 10);
    }

Those `assert` checks carry the meaning "assuming that both of the ages are greater than or equal to zero". It can also be thought of as meaning "this function can work correctly only if both of the ages are greater than or equal to zero".

Each `assert` checks its assumption and terminates the program with an `AssertError` when it is not valid:

    core.exception.AssertError@deneme(2): Assertion failure

The part after the `@` character in the message indicates the source file and the line number of the `assert` check that failed. According to the output above, the `assert` that failed is on line 2 of file `deneme.d`.

The other syntax of `assert` allows printing a custom message when the `assert` check fails:

        assert(first >= 0, "Age cannot be negative.");

The output:

    core.exception.AssertError@deneme.d(2): Age cannot be negative.

Sometimes it is thought to be impossible for the program to ever enter a code path. In such cases it is common to use the literal `false` as the logical expression to fail an `assert` check. For example, to indicate that `applyCommand()` function is never expected to be called with a command other than "sing" and "dance", and to guard against such a possibility, an `assert(false)` can be inserted into the impossible branch:

    void applyCommand(string command) {
        if (command == "sing") {
            robotSing();

        } else if (command == "dance") {
            robotDance();

        } else {
            assert(false);
        }
    }

The function is guaranteed to work with the only two commands that it knows about. (Note: An alternative choice here would be to use a `final switch` statement.)

##### `static assert`

Since `assert` checks are for correct execution of programs, they are applied when the program is actually running. There can be other checks that are about the structure of the program, which can be applied even at compile time.

`static assert` is the counterpart of `assert` that is applied at compile time. The advantage is that it does not allow even compiling a program that would have otherwise run incorrectly. A natural requirement is that it must be possible to evaluate the logical expression at compile time.

For example, assuming that the title of a menu will be printed on an output device that has limited width, the following `static assert` ensures that it will never be wider than that limit:

        enum dstring menuTitle = "Command Menu";
        static assert(menuTitle.length <= 16);

Note that the string is defined as `enum` so that its length can be evaluated at compile time.

Let's assume that a programmer changes that title to make it more descriptive:

        enum dstring menuTitle = "Directional Commands Menu";
        static assert(menuTitle.length <= 16);

The `static assert` check prevents compiling the program:

    Error: static assert  (25u <= 16u) is false

This would remind the programmer of the limitation of the output device.

`static assert` is even more useful when used in templates. We will see templates in later chapters.

##### `assert` even if absolutely true

I emphasize "absolutely true" because assumptions about the program are never expected to be false anyway. A large set of program errors are caused by assumptions that are thought to be absolutely true.

For that reason, take advantage of `assert` checks even if they feel unnecessary. Let's look at the following function that returns the days of months in a given year:

    int[] monthDays(int year) {
        int[] days = [
            31, februaryDays(year),
            31, 30, 31, 30, 31, 31, 30, 31, 30, 31
        ];

        assert((sum(days) == 365) ||
               (sum(days) == 366));

        return days;
    }

That `assert` check may be seen as unnecessary because the function would naturally return either 365 or 366. However, those checks are guarding against potential mistakes even in the `februaryDays()` function. For example, the program would be terminated if `februaryDays()` returned 30.

Another seemingly unnecessary check can ensure that the length of the slice would always be 12:

        assert(days.length == 12);

That way, deleting or adding elements to the slice unintentionally would also be caught. Such checks are important tools toward program correctness.

`assert` is also the fundamental tool that is used in unit testing and contract programming, both of which will be covered in later chapters.

##### No value nor side effect

We have seen that expressions produce values or make side effects. `assert` checks do not have values nor should they have any side effects.

The D language requires that the evaluation of the logical expression must not have any side effect. `assert` must remain as a passive observer of program state.

##### Disabling `assert` checks

Since `assert` is about program correctness, they can be seen as unnecessary once the program has been tested sufficiently. Further, since `assert` checks produce no values nor they have side effects, removing them from the program should not make any difference.

The compiler switch `-release` causes the `assert` checks to be ignored as if they have never been included in the program:

    $ dmd deneme.d -release

This would allow programs to run faster by not evaluating potentially slow logical expressions of the `assert` checks.

As an exception, the `assert` checks that have the literal `false` (or 0) as the logical expression are not disabled even when the program is compiled with `‑release`. This is because `assert(false)` is for ensuring that a block of code is never reached, and that should be prevented even for the `‑release` compilations.

##### `enforce` for throwing exceptions

Not every unexpected situation is an indication of a program error. Programs may also experience unexpected inputs and unexpected environmental state. For example, the data that is entered by the user should not be validated by an `assert` check because invalid data has nothing to do with the correctness of the program itself. In such cases it is appropriate to throw exceptions like we have been doing in previous programs.

`std.exception.enforce` is a convenient way of throwing exceptions. For example, let's assume that an exception must be thrown when a specific condition is not met:

        if (count < 3) {
            throw new Exception("Must be at least 3.");
        }

`enforce()` is a wrapper around the condition check and the `throw` statement. The following is the equivalent of the previous code:

    import std.exception;
    // ...
        enforce(count >= 3, "Must be at least 3.");

Note how the logical expression is negated compared to the `if` statement. It now spells out what is being enforced.

##### How to use

`assert` is for catching programmer errors. The conditions that `assert` guards against in the `monthDays()` function and the `menuTitle` variable above are all about programmer mistakes.

Sometimes it is difficult to decide whether to rely on an `assert` check or to throw an exception. The decision should be based on whether the unexpected situation is due to a problem with how the program has been coded.

Otherwise, the program must throw an exception when it is not possible to accomplish a task. `enforce()` is expressive and convenient when throwing exceptions.

Another point to consider is whether the unexpected situation can be remedied in some way. If the program can not do anything special, even by simply printing an error message about the problem with some input data, then it is appropriate to throw an exception. That way, callers of the code that threw the exception can catch it to do something special to recover from the error condition.

##### Problemler

1. The following program includes a number of `assert` checks. Compile and run the program to discover its bugs that are revealed by those `assert` checks.

   The program takes a start time and a duration from the user and calculates the end time by adding the duration to the start time:

       10 hours and 8 minutes after 06:09 is 16:17.

   Note that this problem can be written in a much cleaner way by defining `struct` types. We will refer to this program in later chapters.

       import std.stdio;
       import std.string;
       import std.exception;

       /* Reads the time as hour and minute after printing a
        * message. */
       void readTime(string message,
                     out int hour,
                     out int minute) {
           write(message, "? (HH:MM) ");

           readf(" %s:%s", &hour, &minute);

           enforce((hour >= 0) && (hour <= 23) &&
                   (minute >= 0) && (minute <= 59),
                   "Invalid time!");
       }

       /* Returns the time in string format. */
       string timeToString(int hour, int minute) {
           assert((hour >= 0) && (hour <= 23));
           assert((minute >= 0) && (minute <= 59));

           return format("%02s:%02s", hour, minute);
       }

       /* Adds duration to start time and returns the result as the
        * third pair of parameters. */
       void addDuration(int startHour, int startMinute,
                        int durationHour, int durationMinute,
                        out int resultHour, out int resultMinute) {
           resultHour = startHour + durationHour;
           resultMinute = startMinute + durationMinute;

           if (resultMinute > 59) {
               ++resultHour;
           }
       }

       void main() {
           int startHour;
           int startMinute;
           readTime("Start time", startMinute, startHour);

           int durationHour;
           int durationMinute;
           readTime("Duration", durationHour, durationMinute);

           int endHour;
           int endMinute;
           addDuration(startHour, startMinute,
                       durationHour, durationMinute,
                       endHour, endMinute);

           writefln("%s hours and %s minutes after %s is %s.",
                    durationHour, durationMinute,
                    timeToString(startHour, startMinute),
                    timeToString(endHour, endMinute));
       }

   Run the program and enter `06:09` as the start time and `1:2` as the duration. Observe that the program terminates normally.

   Note: You may notice a problem with the output. Ignore that problem for now as you will discover it by the help of `assert` checks soon.

2. This time enter `06:09` and `15:2`. Observe that the program is terminated by an `AssertError`. Go to the line of the program that is indicated in the assert message and see which one of the `assert` checks have failed. It may take a while to discover the cause of this particular failure.
3. Enter `06:09` and `20:0` and observe that the same `assert` check still fails and fix that bug as well.
4. Modify the program to print the times in 12-hour format with an "am" or "pm" indicator.

... çözümler

Copyright © 1999-2026 by the D Language Foundation | Page generated by Ddoc on Mon Aug 17 18:57:12 2026