Functional programming

D puts an emphasis on functional programming and provides first-class support for development in a functional style. See:

Pure functions

In D a function can be declared as pure, which implies that given the same input parameters, the same output is always generated. pure functions cannot access or change any mutable global state and are thus just allowed to call other functions which are pure themselves.

int add(int lhs, int rhs) pure {
    impureFunction(); // ERROR: unable to call impureFunction here
    return lhs + rhs;
}

This variant of add is called a strongly pure function because it returns a result dependent only on its input parameters without modifying them. D also allows the definition of weakly pure functions which might have mutable parameters:

void add(ref int result, int lhs, int rhs) pure {
    result = lhs + rhs;
}

These functions are still considered pure and can't access or change any mutable global state. Only passed-in mutable parameters can be altered. A strongly pure function can call a weakly pure function, because only temporary state is changed:

int add(int lhs, int rhs) pure {
    int result;
    add(result, lhs, rhs);
    return result;
}

Pure functions can allocate memory, and the result can be implicitly converted to other type qualifiers. For example, when the result is a pointer to mutable data, it can convert to immutable. This is because there are no mutable references to the result remaining after the call.

int* heap(int v) pure => new int(v);

immutable int* p = heap(42);

Due to the constraints imposed by pure, pure functions are ideal for multi-threading environments to prevent data races by design. Additionally pure functions can be cached easily and allow a range of compiler optimizations.

The pure attribute is automatically inferred by the compiler for templated, nested or literal functions and auto functions, where applicable (this is also true for @safe, nothrow, and @nogc).

In-depth

rdmd playground.d