Skip to content
Exception Handling and Contracts
step 1/5

Reading — step 1 of 5

Learn

~1 min readStructs vs Classes and Errors

D uses Java-style exceptions. All exceptions extend Throwable (split into Exception for recoverable and Error for unrecoverable).

import std.stdio, std.conv;

int parsePort(string s) {
    int n = to!int(s);          // throws ConvException on failure
    if (n < 1 || n > 65535)
        throw new Exception("port out of range");
    return n;
}

void main() {
    try {
        int p = parsePort("abc");
    } catch (Exception e) {
        writeln("failed: ", e.msg);
    } finally {
        // cleanup
    }
}

Custom exceptions — extend Exception:

class NotFoundException : Exception {
    string id;
    this(string id) {
        super("not found: " ~ id);
        this.id = id;
    }
}

Contracts — D's design-by-contract built in:

int divide(int a, int b)
    in { assert(b != 0, "divisor must be nonzero"); }
    out (result) { assert(result * b + a % b == a); }
do {
    return a / b;
}
  • in — preconditions, checked on entry
  • out — postconditions, checked on return (with the result)
  • do — body (used to be body, now reserved)

Contracts are runtime assertions by default but the compiler can elide them in release builds. Useful for catching bugs during development.

scope statements — guaranteed cleanup:

void open() {
    auto file = openFile();
    scope (exit) file.close();           // always runs
    scope (success) commitTransaction();  // only on normal return
    scope (failure) rollback();           // only on exception
    // ... use file ...
}

Cleaner than try/finally for resource management.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…