D puts an emphasis on functional programming and provides first-class support for development in a functional style. See:
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
).