Functions

7.1 Basics

int add(int a, int b) { return a + b; }
void greet(string name = "World") { writeln("Hello, ", name); }   // default argument
auto multiply(int a, int b) => a * b;                             // short syntax (2.098+)
auto inferred(int x) { return x * 2.5; }                          // return type inference

7.2 Parameter Storage Classes

Pass by value (copy) Pass by reference (alias the caller's variable)

Reference, reset to .init on entry: output parameter const scope (read-only input; with -preview=in it may pass by ref)

Argument evaluated only when used (a delegate under the hood)

Reference won't escape the function (DIP1000) return ref / return scope

Returned reference tied to the parameter's lifetime (templates) ref for lvalues, value for rvalues

const / immutable / shared / inout

void increment(ref int x) { x++; }
void getPair(out int a, out int b) { a = 1; b = 2; }
void log(lazy string msg) { if (debugEnabled) writeln(msg); }   // msg is only evaluated if needed

int v = 1;
increment(v);
int p, q;
getPair(p, q);
log("expensive " ~ computeString());

7.3 Variadic Functions

int sum(int[] nums...) { int t; foreach (n; nums) t += n; return t; }  // typesafe variadic
writeln(sum(1, 2, 3));

void printAll(T...)(T args) { foreach (a; args) write(a, " "); }      // variadic template
printAll(1, "two", 3.0);

extern(C) int printf(const char*, ...);   // C-style variadics

7.4 Nested Functions and Function Literals

int outer(int x)
{
    int helper(int y) { return x + y; }    // nested: can access outer's locals
    return helper(10);
}

auto f = function int(int a) { return a * 2; };   // function pointer (no context)
auto g = delegate int(int a) { return a * 2; };   // delegate (has context)
auto h = (int a) => a * 2;                        // lambda
alias Fn = int function(int);

7.5 Overloading

Overload resolution: exact match > match with qualifier conversion > implicit conversion.

void show(int x) { writeln("int"); }
void show(string x) { writeln("string"); }
void show(double x) { writeln("double"); }

7.6 Returning Multiple Values

import std.typecons : tuple, Tuple;
auto divmod(int a, int b) { return tuple(a / b, a % b); }
auto res = divmod(17, 5);
writeln(res[0], " ", res[1]);
auto named = Tuple!(int, "q", int, "r")(3, 2);
writeln(named.q);

7.7 Properties

Any function with zero (or one, for setters) arguments can be called without parentheses. @property is mostly conventional.

struct Temperature
{
    private double celsius;
    @property double fahrenheit() const { return celsius * 9 / 5 + 32; }
    @property void fahrenheit(double f) { celsius = (f - 32) * 5 / 9; }
}
Temperature t;
t.fahrenheit = 212;
writeln(t.fahrenheit);

7.8 Recursion

ulong factorial(ulong n) { return n <= 1 ? 1 : n * factorial(n - 1); }