Movatterモバイル変換


[0]ホーム

URL:


D Logo
Menu
Search

Language Reference

table of contents

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 usinga local clone.

Functions

Contents
  1. Function Declarations
    1. Function Bodies
    2. Function Prototypes
  2. Function Contracts
    1. Preconditions
    2. Postconditions
    3. Example
    4. In, Out and Inheritance
  3. Function Return Values
  4. Pure Functions
    1. Strong vs Weak Purity
    2. Special Cases
    3. Pure Factory Functions
    4. Optimization
  5. Nothrow Functions
  6. Ref Functions
  7. Auto Functions
  8. Auto Ref Functions
  9. Inout Functions
  10. Optional Parentheses
  11. Property Functions
  12. Virtual Functions
    1. Covariance
    2. Calling Base Class Methods
    3. Overload Sets and Overriding
    4. Default Values
    5. Inherited Attributes
    6. Restrictions
  13. Inline Functions
  14. Function Overloading
    1. Overload Sets
  15. Function Parameters
    1. Parameter Storage Classes
    2. In Parameters
    3. Ref and Out Parameters
    4. Lazy Parameters
    5. Default Arguments
    6. Return Ref Parameters
    7. Scope Parameters
    8. Return Scope Parameters
    9. Ref Return Scope Parameters
    10. Inferredscope parameters inpure functions
    11. User-Defined Attributes for Parameters
    12. Variadic Functions
    13. Hidden Parameters
  16. Ref Scope Return Cases
    1. Definitions
    2. Classification
    3. Mapping Syntax Onto Classification
    4. Member Functions
    5. P and ref
    6. Covariance
  17. Local Variables
    1. Local Static Variables
  18. Nested Functions
    1. Declaration Order
  19. Function Pointers, Delegates and Closures
    1. Function Pointers
    2. Delegates & Closures
    3. Method Delegates
    4. Initialization
    5. Anonymous Functions and Anonymous Delegates
  20. main() Function
    1. extern(C) main() Function
  21. Function Templates
  22. Compile Time Function Execution (CTFE)
    1. String Mixins and Compile Time Function Execution
  23. No-GC Functions
  24. Function Safety
    1. Safe Functions
    2. Trusted Functions
    3. System Functions
    4. Safe Interfaces
    5. Safe Values
    6. Null Dereferences
    7. Safe Aliasing
  25. Function Attribute Inference
  26. Uniform Function Call Syntax (UFCS)

Function Declarations

FuncDeclaration:StorageClassesoptBasicTypeFuncDeclaratorFunctionBodyStorageClassesoptBasicTypeFuncDeclaratorMissingFunctionBodyAutoFuncDeclaration
AutoFuncDeclaration:StorageClassesIdentifierFuncDeclaratorSuffixFunctionBody
FuncDeclarator:TypeSuffixesoptIdentifierFuncDeclaratorSuffix
FuncDeclaratorSuffix:ParametersMemberFunctionAttributesoptTemplateParametersParametersMemberFunctionAttributesoptConstraintopt

Function Parameters

Parameters:(ParameterListopt)
ParameterList:ParameterParameter,ParameterListoptVariadicArgumentsAttributesopt...
Parameter:ParameterDeclarationParameterDeclaration...ParameterDeclaration=AssignExpressionParameterDeclaration=AssignExpression...
ParameterDeclaration:ParameterAttributesoptBasicTypeDeclaratorParameterAttributesoptType
ParameterAttributes:ParameterStorageClassUserDefinedAttributeParameterAttributesParameterStorageClassParameterAttributesUserDefinedAttribute
ParameterStorageClass:autoTypeCtorfinalinlazyoutrefreturnscope
VariadicArgumentsAttributes:VariadicArgumentsAttributeVariadicArgumentsAttributeVariadicArgumentsAttributes
VariadicArgumentsAttribute:constimmutablereturnscopeshared
Note: In D2, declaring a parameterfinal is a semantic error, but not a parse error.

See also:parameter storage classes.

Function Attributes

FunctionAttributes:FunctionAttributeFunctionAttributeFunctionAttributes
FunctionAttribute:FunctionAttributeKwdPropertyAtAttribute
MemberFunctionAttributes:MemberFunctionAttributeMemberFunctionAttributeMemberFunctionAttributes
MemberFunctionAttribute:constimmutableinoutreturnscopesharedFunctionAttribute

Function Bodies

FunctionBody:SpecifiedFunctionBodyShortenedFunctionBody
SpecifiedFunctionBody:dooptBlockStatementFunctionContractsoptInOutContractExpressiondooptBlockStatementFunctionContractsoptInOutStatementdoBlockStatement
ShortenedFunctionBody:InOutContractExpressionsopt=>AssignExpression;

Examples:

int hasSpecifiedBody() {return 1; }int hasShortenedBody() => 1;// equivalent

TheShortenedFunctionBody form implies areturn statement. This syntax also applies forfunction literals.

Function Prototypes

MissingFunctionBody:;FunctionContractsoptInOutContractExpression;FunctionContractsoptInOutStatement

Function declarations with aMissingFunctionBody, e.g.:

int foo();

that are not declared asabstract are expected to have their implementations elsewhere, and that implementation will be provided at the link step. This enables an implementation of a function to be completely hidden from the user of it, and the implementation may be in another language such as C, assembler, etc. Typically a function prototype would have non-extern(D)linkage.

A function prototype can haveextern(D) linkage. This is useful forD interface files.

Function Contracts

FunctionContracts:FunctionContractFunctionContractFunctionContracts
FunctionContract:InOutContractExpressionInOutStatement
InOutContractExpressions:InOutContractExpressionInOutContractExpressionInOutContractExpressions
InOutContractExpression:InContractExpressionOutContractExpression
InOutStatement:InStatementOutStatement

Function Contracts specify the preconditions and postconditions of a function. They are used inContract Programming.

Preconditions and postconditions do not affect the type of the function.

Preconditions

InContractExpression:in (AssertArguments)
InStatement:inBlockStatement

AnInContractExpression is a precondition.

AnInStatement is also a precondition. AnyAssertExpression appearing in anInStatement will be anInContractExpression.

Preconditions must semantically be satisfied before the function starts executing. If a precondition fails, the program enters anInvalid State.

Implementation Defined: Whether the preconditions are actually run or not is implementation defined. This is usually selectable with a compiler switch. Its behavior upon precondition failure is also usually selectable with a compiler switch. One option is to throw anAssertError with a message consisting of the optional secondAssignExpression.
Best Practices: Use preconditions to validate that input arguments have values that are expected by the function.
Best Practices: Since preconditions may or may not be actually checked at runtime, avoid using preconditions that have side effects.

The expression form is:

in (expression)in (expression,"failure string"){    ...function body...}

The block statement form is:

in{    ...contract preconditions...}do{    ...function body...}

Postconditions

OutContractExpression:out ( ;AssertArguments)out (Identifier;AssertArguments)
OutStatement:outBlockStatementout(Identifier)BlockStatement

AnOutContractExpression is a postcondition.

AnOutStatement is also a postcondition. AnyAssertExpression appearing in anOutStatement will be anOutContractExpression.

Postconditions must semantically be satisfied after the function finishes executing. If a postcondition fails, the program enters anInvalid State.

Implementation Defined: Whether the postconditions are actually run or not is implementation defined. This is usually selectable with a compiler switch. Its behavior upon postcondition failure is also usually selectable with a compiler switch. One option is to throw anAssertError with a message consisting of the optional secondAssignExpression.
Best Practices: Use postconditions to validate that on leaving the function:
Best Practices: Since postconditions may or may not be actually checked at runtime, avoid using postconditions that have side effects.

The expression form is:

out (identifier; expression)out (identifier; expression,"failure string")out (; expression)out (; expression,"failure string"){    ...function body...}

The block statement form is:

out{    ...contract postconditions...}out (identifier){    ...contract postconditions...}do{    ...function body...}

The optional identifier in either type of postcondition is set to the return value of the function, and can be accessed from within the postcondition. It is implicitlyconst.

Example

int fun(refint a,int b)in (a > 0)in (b >= 0,"b cannot be negative!")out (r; r > 0,"return must be positive")out (; a != 0){// function body}
int fun(refint a,int b)in{assert(a > 0);assert(b >= 0,"b cannot be negative!");}out (r){assert(r > 0,"return must be positive");assert(a != 0);}do{// function body}

The two functions are identical semantically.

In, Out and Inheritance

If a function in a derived class overrides a function from its super class, then only the preconditions of one of the function and its overridden functions must be satisfied. Overriding functions then becomes a process ofloosening the preconditions.

A function without preconditions means its precondition is always satisfied. Therefore if any function in an inheritance hierarchy has no preconditions, then any preconditions on functions overriding it have no meaningful effect.

Conversely, all of the postconditions of the function and its overridden functions must to be satisfied. Adding overriding functions then becomes a processes oftightening the postconditions.

Function Return Values

Onereturn statement per execution path is required if the function specifies a return type that is notvoid, unless:

Simple forms of the first 3 cases above can be recognized by the compiler, but not all.

int error(int i){if (i & 1)        i++;elsereturn i;// Error: no return statement}
int f(int i){if (i >= 0)return i;assert(0);// OK, no return needed}

Function return values not marked asref are considered to be rvalues by the calling function. This means they cannot be passed by reference to other functions.

Pure Functions

Pure functions are annotated with thepure attribute. Pure functions cannot directly access global or static mutable state. Pure functions can only call pure functions.

Pure functions can:

int x;immutableint y;pureint foo(int i){    i++;// ok, modifying local state//x = i; // error, modifying global state//i = x; // error, reading mutable global state    i = y;// ok, reading immutable global statethrownew Exception("failed");// ok}

A pure function can override an impure function, but cannot be overridden by an impure function. I.e. it is covariant with an impure function.

Strong vs Weak Purity

Aweakly pure function has parameters with mutable indirections. Program state can be modified transitively through the matching argument.

pure size_t foo(int[] arr){    arr[] += 1;return arr.length;}int[] a = [1, 2, 3];foo(a);assert(a == [2, 3, 4]);

Astrongly pure function has no parameters with mutable indirections and cannot modify any program state external to the function.

struct S {double x; }pure size_t foo(immutable(int)[] arr,int num, S val){//arr[num] = 1; // compile error    num = 2;// has no side effect on the caller side    val.x = 3.14;// dittoreturn arr.length;}

A strongly pure function can call a weakly pure function.

Special Cases

A pure function can:

Undefined Behavior: occurs if these flags are not restored to their initial state upon function exit. It is the programmer's responsibility to ensure this. Setting these flags is not allowed in@safe code.

Debugging

A pure function can perform impure operations in statements that are in aConditionalStatement controlled by aDebugCondition.

Best Practices: this relaxation of purity checks inDebugConditions is intended solely to make debugging programs easier.
pureint foo(int i){debug writeln("i = ", i);// ok, impure code allowed in debug statement    ...}

Nested Functions

Nested functions inside a pure function are implicitly marked as pure.

pureint foo(int x,immutableint y){int bar()// implicitly marked as pure, to be "weakly pure"// since hidden context pointer to foo stack context is mutable    {        x = 10;// can access states in enclosing scope// through the mutable context pointerreturn x;    }pragma(msg,typeof(&bar));// int delegate() pureint baz()immutable// qualifies hidden context pointer with immutable,// and has no other parameters, therefore "strongly pure"    {//return x; // error, cannot access mutable data// through the immutable context pointerreturn y;// ok    }// can call pure nested functionsreturn bar() + baz();}

Pure Factory Functions

Apure factory function is a strongly pure function that returns a result that has only mutable indirections. All mutable memory returned by the call cannot be referenced by any other part of the program, i.e. it is newly allocated by the function. The mutable references of the result similarly cannot refer to any object that existed before the function call. This allows the result to be implicitly cast from anything toimmutable orconst shared, and fromshared andconst shared to (unshared)const. For example:

struct List {int payload; List* next; }pure List* make(int a,int b){auto result =new List(a,null);    result.next =new List(b,null);return result;}void main(){auto list = make(1, 2);pragma(msg,typeof(list));// List*immutable ilist = make(1, 2);pragma(msg,typeof(ilist));// immutable List*pragma(msg,typeof(ilist.next));// immutable List*}

All references inmake's result refer toList objects created bymake, and no other part of the program refers to any of these objects. Hence the result can initialize an immutable variable.

This does not affect anyException orError thrown from the function.

Optimization

Implementation Defined: An implementation may assume that a strongly pure function called with arguments that have only immutable indirections (or none) that returns a result without mutable indirections will have the same effect for all invocations with equivalent arguments. It is allowed to memoize the result of the function under the assumption that equivalent arguments always produce equivalent results.
int a(int)pure;// no mutable indirectionsint b(const Object)pure;// depends on argument passedimmutable(Object) c(immutable Object)pure;// always memoizablevoid g();void f(int n,const Object co,immutable Object io){constint x = a(n);    g();// `n` does not change between calls to `a`int i = a(n);// same as `i = x`constint y = b(co);// `co` may have mutable indirection    g();// may change fields of `co` through another reference    i = b(co);// call is not memoizable, result may differconstint z = b(io);    i = b(io);// same as `i = z`}

Such a function may still have behavior inconsistent with memoization by e.g. usingcasts or by changing behavior depending on the address of its parameters. An implementation is currently not required to enforce validity of memoization in all cases.

If a function throws anException or anError, the assumptions related to memoization do not carry to the thrown exception.

Pure destructors do not benefit of special elision.

Nothrow Functions

Nothrow functions can only throw exceptions derived fromclass Error.

Nothrow functions are covariant with throwing ones.

Ref Functions

Aref function returns by reference (instead of by value). The return value of aref function must be an lvalue (whereas the return value of a non-ref function can be an rvalue, too). An expression formed by calling aref function is an lvalue (whereas an expression formed by calling a non-ref function is an rvalue).

int *p;refint foo(){    p =newint(2);return *p;}void main(){int i = foo();assert(i == 2);    foo() = 3;// reference returns can be lvaluesassert(*p == 3);}

Returning a reference to an expired function context is not allowed. This includes local variables, temporaries and parameters that are part of an expired function context.

refint sun(){int i;return i;// error, escaping a reference to local variable i}

Aref parameter may not be returned byref, unless it isreturn ref.

refint moon(refint i){return i;// error}

Auto Functions

Auto functions have their return type inferred from anyReturnStatements in the function body.

An auto function is declared without a return type. Auto functions can use any validStorageClass, not justauto.

If there are multipleReturnStatements, the types of them must be implicitly convertible to a common type. If there are noReturnStatements, the return type is inferred to bevoid.

auto foo(int x) {return x + 3; }// inferred to be intpure bar(int x) {return x;return 2.5; }// inferred to be double
Note: Return type inference also triggersattribute inference.

Auto Ref Functions

Auto ref functions can infer their return type just asauto functions do. In addition, they becomeref functions if all of these apply:

The ref-ness of a function is determined from allReturnStatements in the function body:

autoref f1(refint x) {return 3;return x; }// ok, value returnautoref f2(refint x) {return x;return 3; }// ok, value returnautoref f3(refint x,refdouble y){return x;return y;// The return type is deduced to be double, but cast(double)x is not an lvalue,// so f3 has a value return.}

Auto ref functions can have an explicit return type.

autorefint bar(refint x) {return x; }// ok, ref returnautorefint foo(double x) {return x; }// error, cannot convert double to int

Inout Functions

For extensive information seeinout type qualifier.

Optional Parentheses

If a function call passes no explicit argument, i.e. it would syntactically use(), then these parentheses may be omitted, similar to a getter invocation of aproperty function. AUFCS call can also omit empty parentheses.

void foo() {}// no argumentsvoid fun(int x = 10) {}void bar(int[] arr) {}void main(){    foo();// OK    foo;// also OK    fun;// OKint[] arr;    arr.bar();// UFCS call    arr.bar;// also OK}

Due to ambiguity, parentheses are required to call a delegate or a function pointer:

void main(){intfunction() fp;assert(fp == 6);// Error, incompatible types int function() and intassert(*fp == 6);// Error, incompatible types int() and intintdelegate() dg;assert(dg == 6);// Error, incompatible types int delegate() and int}

If a function returns a delegate or a function pointer, any parentheses apply first to the function call, not the result. Two sets of parentheses are required to call the result directly:

int getNum() {return 6; }intfunction() getFunc() {return &getNum; }void main(){intfunction() fp;    fp = getFunc;// implicit callassert(fp() == 6);    fp = getFunc();// explicit callassert(fp() == 6);int x = getFunc()();assert(x == 6);}
struct S{int getNum() {return 6; }intdelegate() getDel()return {return &getNum; }}void main(){    S s;intdelegate() dg;    dg = s.getDel;// implicit callassert(dg() == 6);    dg = s.getDel();// explicit callassert(dg() == 6);int y = s.getDel()();assert(y == 6);}

Property Functions

WARNING: The definition and usefulness of property functions is being reviewed, and the implementation is currently incomplete. Using property functions is not recommended until the definition is more certain and implementation more mature.

Properties are functions that can be syntactically treated as if they were fields or variables. Properties can be read from or written to. A property is read by calling a method or function with no arguments; a property is written by calling a method or function with its argument being the value it is set to.

Simple getter and setter properties can be written usingUFCS. These can be enhanced with the additon of the@property attribute to the function, which adds the following behaviors:

A simple property would be:

struct Foo{    @propertyint data() {return m_data; }// read property    @propertyint data(int value) {return m_data = value; }// write propertyprivate:int m_data;}

To use it:

int test(){    Foo f;    f.data = 3;// same as f.data(3);return f.data + 3;// same as return f.data() + 3;}

The absence of a read method means that the property is write-only. The absence of a write method means that the property is read-only. Multiple write methods can exist; the correct one is selected using the usual function overloading rules.

In all the other respects, these methods are like any other methods. They can be static, have different linkages, have their address taken, etc.

The built in properties.sizeof,.alignof, and.mangleof may not be declared as fields or methods in structs, unions, classes or enums.

If a property function has no parameters, it works as a getter. If has exactly one parameter, it works as a setter.

Virtual Functions

Virtual functions are class member functions that are called indirectly through a function pointer table, called avtbl[], rather than directly. Member functions that are virtual can be overridden in a derived class:

class A{void foo(int x) {}}class B : A{overridevoid foo(int x) {}//override void foo() {} // error, no foo() in A}void test(){    A a =new B();    a.foo(1);// calls B.foo(int)}

Theoverride attribute is required when overriding a function. This is useful for catching errors when a base class's member function has its parameters changed, and all derived classes need to have their overriding functions updated.

Thefinal method attribute prevents a subclass from overriding the method.

The following are not virtual:

Example:

class A{int def() { ... }finalint foo() { ... }finalprivateint bar() { ... }privateint abc() { ... }}class B : A{overrideint def() { ... }// ok, overrides A.defoverrideint foo() { ... }// error, A.foo is finalint bar() { ... }// ok, A.bar is final private, but not virtualint abc() { ... }// ok, A.abc is not virtual, B.abc is virtual}void test(){    A a =new B;    a.def();// calls B.def    a.foo();// calls A.foo    a.bar();// calls A.bar    a.abc();// calls A.abc}

Member functions withObjective-C linkage are virtual even if marked withfinal orstatic, and can be overridden.

Covariance

An overriding function may be covariant with the overridden function. A covariant function has a type that is implicitly convertible to the type of the overridden function.

class A { }class B : A { }class Foo{    A test() {returnnull; }}class Bar : Foo{// overrides and is covariant with Foo.test()override B test() {returnnull; }}

Calling Base Class Methods

To directly call a member function of a base classBase, writeBase. before the function name. This avoids dynamic dispatch through a function pointer. For example:

class B{int foo() {return 1; }}class C : B{overrideint foo() {return 2; }void test()    {assert(B.foo() == 1);// translated to this.B.foo(), and// calls B.foo statically.assert(C.foo() == 2);// calls C.foo statically, even if// the actual instance of 'this' is D.    }}class D : C{overrideint foo() {return 3; }}void main(){auto d =new D();assert(d.foo() == 3);// calls D.fooassert(d.B.foo() == 1);// calls B.fooassert(d.C.foo() == 2);// calls C.foo    d.test();}

Base class methods can also be called through thesuper reference.

Implementation Defined: Normally calling a virtual function implies getting the address of the function at runtime by indexing into the class'svtbl[]. If the implementation can determine that the called virtual function will be statically known, such as if it isfinal, it can use a direct call instead.

Overload Sets and Overriding

When doing overload resolution, the functions in the base class are not considered, as they are not in the sameOverload Set:

class A{int foo(int x) { ... }int foo(long y) { ... }}class B : A{overrideint foo(long x) { ... }}void test(){    B b =new B();    b.foo(1);// calls B.foo(long), since A.foo(int) is not considered    A a = b;    a.foo(1);// issues runtime error (instead of calling A.foo(int))}

To include the base class's functions in the overload resolution process, use anAliasDeclaration:

class A{int foo(int x) { ... }int foo(long y) { ... }}class B : A{alias foo = A.foo;overrideint foo(long x) { ... }}void test(){    A a =new B();    a.foo(1);// calls A.foo(int)    B b =new B();    b.foo(1);// calls A.foo(int)}

If such anAliasDeclaration is not used, the derived class's functions completely override all the functions of the same name in the base class, even if the types of the parameters in the base class functions are different. It is illegal if, through implicit conversions to the base class, those other functions do get called:

class A{voidset(long i) { }void set(int i)  { }}class B : A{overridevoid set(long i) { }}void test(){    A a =new B;    a.set(3);// error, use of A.set(int) is hidden by B// use 'alias set = A.set;' to introduce base class overload set}

Default Values

A function parameter's default value is not inherited:

class A{voidfoo(int x = 5) { ... }}class B : A{void foo(intx = 7) { ... }}class C : B{void foo(intx) { ... }}void test(){    A a =new A();    a.foo();// calls A.foo(5)    B b =new B();    b.foo();// calls B.foo(7)    C c =new C();    c.foo();// error, need an argument for C.foo}

Inherited Attributes

An overriding function inherits any unspecifiedFunctionAttributes from the attributes of the overridden function.

class B{void foo()purenothrow @safe {}}class D : B{overridevoid foo() {}}void main(){auto d =new D();pragma(msg,typeof(&d.foo));// prints "void delegate() pure nothrow @safe" in compile time}

Restrictions

The attributes@disable anddeprecated are not allowed on overriding functions.

Rationale: To stop the compilation or to output the deprecation message, the implementation must be able to determine the target of the call, which can't be guaranteed when it is virtual.
class B{void foo() {}}class D : B{    @disableoverridevoid foo() {}// error, can't apply @disable to overriding function}

Inline Functions

The compiler makes the decision whether to inline a function or not. This decision may be controlled bypragma(inline).

Implementation Defined: Whether a function is inlined or not is implementation defined, though anyFunctionLiteral should be inlined when used in its declaration scope.

Function Overloading

Function overloading occurs when two or more functions in the same scope have the same name. The function selected is the one that is thebest match to the arguments. The matching levels are:

  1. No match
  2. Match with implicit conversions
  3. Match with qualifier conversion (if the argument type isqualifier-convertible to the parameter type)
  4. Exact match

Named arguments are resolved for a candidate according toMatching Arguments to Parameters. If this fails (for example, because the overload does not have a parameter matching a named argument), the level isno match. Other than that, named arguments do not affect the matching level.

Each argument (including anythis reference) is compared against the function's corresponding parameter to determine the match level for that argument. The match level for a function is theworst match level of each of its arguments.

Literals do not matchref orout parameters.

scope parameter storage class does not affect function overloading.

If two or more functions have the same match level, thenpartial ordering is used to disambiguate to find the best match. Partial ordering finds the most specialized function. If neither function is more specialized than the other, then it is an ambiguity error. Partial ordering is determined for functionsf andg by taking the parameter types off, constructing a list of arguments by taking the default values of those types, and attempting to match them againstg. If it succeeds, theng is at least as specialized asf. For example:

class A { }class B : A { }class C : B { }void foo(A);void foo(B);void test(){    C c;/* Both foo(A) and foo(B) match with implicit conversions (level 2).     * Applying partial ordering rules,     * foo(B) cannot be called with an A, and foo(A) can be called     * with a B. Therefore, foo(B) is more specialized, and is selected.     */    foo(c);// calls foo(B)}

A function with a variadic argument is considered less specialized than a function without.

A static member function can be overloaded with a member function. The struct, class or union of the static member function is inferred from the type of thethis argument.

struct S {void eggs(int);staticvoid eggs(long);}S s;s.eggs(0);// calls void eggs(int);S.eggs(0);// error: need `this`s.eggs(0L);// calls static void eggs(long);S.eggs(0L);// calls static void eggs(long);struct T {void bacon(int);staticvoid bacon(int);}T t;t.bacon(0);// error: ambiguousT.bacon(0);// error: ambiguous
Rationale: A static member function that doesn't need thethis parameter does not need to pass it.

Overload Sets

Functions declared at the same scope overload against each other, and are called anOverload Set. An example of an overload set are functions defined at module level:

module A;void foo() { }void foo(long i) { }

A.foo() andA.foo(long) form an overload set. A different module can also define another overload set of functions with the same name:

module B;class C { }void foo(C) { }void foo(int i) { }

and A and B can be imported by a third module, C. Both overload sets, theA.foo overload set and theB.foo overload set, are found when searching for symbolfoo. An instance offoo is selected based on it matching in exactly one overload set:

import A;import B;void bar(C c ,long i){    foo();// calls A.foo()    foo(i);// calls A.foo(long)    foo(c);// calls B.foo(C)    foo(1,2);// error, does not match any foo    foo(1);// error, matches A.foo(long) and B.foo(int)    A.foo(1);// calls A.foo(long)}

Even thoughB.foo(int) is a better match than A.foo(long) forfoo(1), it is an error because the two matches are in different overload sets.

Overload sets can be merged with an alias declaration:

import A;import B;alias foo = A.foo;alias foo = B.foo;void bar(C c){    foo();// calls A.foo()    foo(1L);// calls A.foo(long)    foo(c);// calls B.foo(C)    foo(1,2);// error, does not match any foo    foo(1);// calls B.foo(int)    A.foo(1);// calls A.foo(long)}

Function Parameters

Parameter Storage Classes

Parameter storage classes arein,out,ref,lazy,return andscope. Parameters can also take the type constructorsconst,immutable,shared andinout.

in,out,ref andlazy are mutually exclusive. The first three are used to denote input, output and input/output parameters, respectively. For example:

int read(inchar[] input,ref size_t count,outint errno);void main(){    size_t a = 42;int b;int r = read("Hello World", a, b);}

read has three parameters.input will only be read and no reference to it will be retained.count may be read and written to, anderrno will be set to a value from within the function.

The argument"Hello World" gets bound to parameterinput,a gets bound tocount andb toerrno.

Parameter Storage Class and Type Constructor Overview
Storage ClassDescription
noneThe parameter will be a mutable copy of its argument.
inThe parameter is an input to the function.
outThe argument must be an lvalue, which will be passed by reference and initialized upon function entry with the default value (T.init) of its type.
refThe parameter is aninput/output parameter, passed by reference.
scope The parameter must not escape the function call (e.g. by being assigned to a global variable). Ignored for any parameter that is not a reference type.
returnParameter may be returned or copied to the first parameter, but otherwise does not escape from the function. Such copies are required not to outlive the argument(s) they were derived from. Ignored for parameters with no references. SeeScope Parameters.
lazyargument is evaluated by the called function and not by the caller
Type ConstructorDescription
constargument is implicitly converted to a const type
immutableargument is implicitly converted to an immutable type
sharedargument is implicitly converted to a shared type
inoutargument is implicitly converted to an inout type

In Parameters

The parameter is an input to the function. Input parameters behave as if they have theconst storage class.

Note: The following requires the-preview=in switch and a compiler compliant withdmd v2.094.0 or higher.

in parameters also behave likescope parameters.

const(int[]) g(inint[] a) @safe{    a[0]++;// Error: cannot modify const expressionreturn a;// Error: scope parameter `a` may not be returned}

Input parameters may also be passed by reference by the compiler. Unlikeref parameters,in parameters can bind to both lvalues and rvalues (such as literals).

Implementation Defined: If the type of the parameter does not fall in one of those categories, whether or not it is passed by reference is implementation defined, and the backend is free to choose the method that will best fit the ABI of the platform.

Ref and Out Parameters

By default, parameters take rvalue arguments. Aref parameter takes an lvalue argument, so changes to its value will operate on the caller's argument.

void inc(refint x){    x += 1;}void seattle(){int z = 3;    inc(z);assert(z == 4);}

Aref parameter can also be returned by reference, seeReturn Ref Parameters.

Anout parameter is similar to aref parameter, except it is initialized bydefault construction upon function invocation.

void zero(outint x){assert(x == 0);}void two(outint x){    x = 2;}void tacoma(){int a = 3;    zero(a);assert(a == 0);int y = 3;    two(y);assert(y == 2);}

For dynamic array and class object parameters, which are always passed by reference,out andref apply only to the reference and not the contents.

Lazy Parameters

An argument to alazy parameter is not evaluated before the function is called. The argument is only evaluated if/when the parameter is evaluated within the function. Hence, alazy argument can be executed 0 or more times.

import std.stdio : writeln;void main(){int x;    3.times(writeln(x++));    writeln("-");    writeln(x);}void times(int n,lazyvoid exp){while (n--)        exp();}

prints to the console:

012−3

Alazy parameter cannot be an lvalue.

The underlying delegate of thelazy parameter may be extracted by using the& operator:

void test(lazyint dg){intdelegate() dg_ = &dg;assert(dg_() == 7);assert(dg == dg_());}void main(){int a = 7;    test(a);}

Alazy parameter of typevoid can accept an argument of any type.

See Also:Lazy Variadic Functions

Default Arguments

Function parameter declarations can have default values:

void foo(int x,int y = 3){    ...}...foo(4);// same as foo(4, 3);

Default parameters are resolved and semantically checked in the context of the function declaration.

module m;privateimmutableint b;purevoid g(int a = b) {}
import m;int b;purevoid f(){    g();// ok, uses m.b}

The attributes of theAssignExpression are applied where the default expression is used.

module m;int b;purevoid g(int a = b) {}
import m;enumint b = 3;purevoid f(){    g();// error, cannot access mutable global `m.b` in pure function}

See also: function type aliaseswith default values.

Return Ref Parameters

Return ref parameters are used withref functions to ensure that the returned reference will not outlive the matching argument's lifetime.

refint identity(returnrefint x) {return x;// pass-through function that does nothing}refint fun() {int x;return identity(x);// Error: escaping reference to local variable x}refint gun(returnrefint x) {return identity(x);// OK}

Returning the address of aref variable is also checked in@safe code.

int* pluto(refint i) @safe{return &i;// error: returning &i escapes a reference to parameter i}int* mars(returnrefint i) @safe{return &i;// OK with -preview=dip1000}
If a function returnsvoid, and the first parameter isref orout, thenall subsequentreturn ref parameters are considered as being assigned tothe first parameter for lifetime checking.
void f(refscopeint* p,returnrefint i) @safe{    p = &i;// OK with -preview=dip1000}void main() @safe{int i;int* p;    f(p, i);// OK, lifetime of p is shorter than i    *p = 5;assert(i == 5);int j;//f(p, j); // error, lifetime of p is longer than j}
Thethis reference parameter to a struct non-static member function isconsidered the first parameter.
struct S{privateint* p;void f(returnrefint i)scope @safe    {        p = &i;// OK with -preview=dip1000    }}void main() @safe{int i;    S s;    s.f(i);// OK, lifetime of `s` is shorter than `i`    *s.p = 2;assert(i == 2);}

If there are multiplereturn ref parameters, the lifetime of the returnvalue is the smallest lifetime of the corresponding arguments.

Neither the type of thereturn ref parameter(s) nor the type of the returnvalue is considered when determining the lifetime of the return value.

It is not an error if the return type does not contain any indirections.

int mercury(returnrefint i){return i;// ok}

Template functions, auto functions, nested functions andlambdas can deduce thereturn attribute.

@safe:refint templateFunction()(refint i){return i;// ok}refauto autoFunction(refint i){return i;// ok}void uranus(){refint nestedFunction(refint i)    {return i;// ok    }auto lambdaFunction =        (refint i)        {return &i;// ok        };}

Struct Return Methods

Struct non-static methods can be marked with thereturn attribute to ensure a returned reference will not outlive the struct instance.

struct S{privateint x;refint get()return {return x; }}refint escape(){    S s;return s.get();// Error: escaping reference to local variable s}

The hiddenthis ref-parameter then becomesreturn ref.

Thereturn attribute can also be used to limit the lifetime of the returned value, even when the method is notref:

struct S{privateint i;int* get()return @safe => &i;}void f() @safe{int* p;    {        S s;int *q = s.get();// OK, q has shorter lifetime than s        p = s.get();// error, p has longer lifetime        p = (new S).get();// OK, heap allocated S    }}

Scope Parameters

Ascope parameter of reference type must not escape the function call (e.g. by being assigned to a global variable). It has no effect for non-reference types.scope escape analysis is only done for@safe functions. For other functionsscope semantics must be manually enforced.

Note:@safe escape analysis is only done with the-preview=dip1000 switch.
@safe:int* gp;void thorin(scopeint*);void gloin(int*);int* balin(scopeint* q,int* r){     gp = q;// error, q escapes to global gp     gp = r;// ok     thorin(q);// ok, q does not escape thorin()     thorin(r);// ok     gloin(q);// error, gloin() escapes q     gloin(r);// ok that gloin() escapes rreturn q;// error, cannot return 'scope' qreturn r;// ok}
Implementation Defined: As ascope parameter must not escape, the compiler can potentially avoid heap-allocating a unique argument to ascope parameter. Due to this, passing an array literal, delegate literal or aNewExpression to a scope parameter may be allowed in a@nogc context.

Return Scope Parameters

Parameters marked asreturn scope that contain indirections can only escape those indirections via the function's return value.

@safe:int* gp;void thorin(scopeint*);void gloin(int*);int* balin(returnscopeint* p){     gp = p;// error, p escapes to global gp     thorin(p);// ok, p does not escape thorin()     gloin(p);// error, gloin() escapes preturn p;// ok}

Class references are considered pointers that are subject toscope.

@safe:class C { }C gp;void thorin(scope C);void gloin(C);C balin(returnscope C p,scope C q, C r){     gp = p;// error, p escapes to global gp     gp = q;// error, q escapes to global gp     gp = r;// ok     thorin(p);// ok, p does not escape thorin()     thorin(q);// ok     thorin(r);// ok     gloin(p);// error, gloin() escapes p     gloin(q);// error, gloin() escapes q     gloin(r);// ok that gloin() escapes rreturn p;// okreturn q;// error, cannot return 'scope' qreturn r;// ok}

return scope can be applied to thethis of class and interface member functions.

class C{    C bofur()returnscope {returnthis; }}

Template functions, auto functions, nested functions andlambdas can deduce thereturn scope attribute.

Ref Return Scope Parameters

It is not possible to have bothreturn ref andreturn scope semantics for the same parameter. When a parameter is passed byref and has both thereturn andscope storage classes, it getsreturn scope semantics if and only if thereturn andscope keywords appear adjacent to each other, in that order. Specifying areturn ref andscope parameter enables returning a reference to a scope pointer. In all other cases, the parameter hasreturn ref semantics and regularscope semantics.

U xerxes(refreturnscope V v)// (1) ref and return scopeU sargon(returnrefscope V v)// (2) return ref and scopestruct S{// note: in struct member functions, the implicit `this` parameter// is passed by `ref`    U xerxes()returnscope;// return scope    U sargon()scopereturn;// return ref, `return` comes after `scope`    U xerxes()returnconstscope;// return ref, `return` and `scope` are not adjacent}

Example of combinations ofreturn scope,return ref, andscope semantics:

@safe:int* globalPtr;struct S{int  val;int* ptr;this(returnscoperefint* p) { ptr = p; }// note: `this` is passed by `ref` in structsint* retRefA()scopereturn// return-ref, scope    {        globalPtr =this.ptr;// disallowed, `this` is `scope`return &this.val;// allowed, `return` means `return ref`    }refint retRefB()scopereturn// return-ref, scope    {        globalPtr =this.ptr;// disallowed, `this` is `scope`returnthis.val;// allowed, `return` means `return ref`    }int* retScopeA()returnscope// ref, return-scope    {return &this.val;// disallowed, escaping a reference to `this`returnthis.ptr;// allowed, returning a `return scope` pointer    }refint retScopeB()returnscope// ref, return-scope    {returnthis.val;// disallowed, escaping a reference to `this`return *this.ptr;// allowed, returning a `return scope` pointer    }refint* retRefScopeC()scopereturn// return-ref, scope    {returnthis.ptr;// allowed, returning a reference to a scope pointer    }}int* retRefA(returnrefscope S s){    globalPtr = s.ptr;// disallowed, `s` is `scope`return &s.val;// allowed, returning a reference to `return ref s`}refint retRefB(returnrefscope S s){    globalPtr = s.ptr;// disallowed, `s` is `scope`return s.val;}int* retScopeA(refreturnscope S s){return &s.val;// disallowed, escaping a reference to `s`return s.ptr;// allowed, returning a `return scope` pointer}refint retScopeB(refreturnscope S s){return s.val;// disallowed, escaping a reference to `s`return *s.ptr;// allowed, returning a `return scope` pointer}refint* retRefScopeC(returnrefscopeint* p){return p;// allowed, returning a reference to a scope pointer}

Inferredscope parameters inpure functions

When a parameter is not marked or inferredscope, it may still be@safe to assign it ascope pointer in a function call. The following conditions need to be met:
Then, the parameter is still treated asscope orreturn scope depending on the return type of the function:
@safe:int dereference(int* x)purenothrow;int* identity(int* x)purenothrow;int* identityThrow(int* x)pure;void assignToRef(int* x,refint* escapeHatch)purenothrow;void assignToPtr(int* x,int** escapeHatch)purenothrow;void cannotAssignTo(int* x,constrefint* noEscapeHatch)purenothrow;int* globalPtr;int* test(scopeint* ptr){int result = dereference(ptr);// allowed, treated as `scope`int* ptr2 = identity(ptr);// allowed, treated as `return scope`int* ptr3 = identityThrow(ptr);// not allowed, can throw an `Exception`    assignToRef(ptr, globalPtr);// not allowed, mutable second parameter    assignToPtr(ptr, &globalPtr);// not allowed, mutable second parameter    cannotAssignTo(ptr, globalPtr);// allowedreturn ptr2;// not allowed, ptr2 is inferred `scope` now}

User-Defined Attributes for Parameters

See also:User-Defined Attributes

Variadic Functions

Variadic Functions take a variable number of arguments. There are three forms:

  1. C-style variadic functions
  2. Variadic functions with type info
  3. Typesafe variadic functions

C-style Variadic Functions

A C-style variadic function is declared with a parameter... as the last function parameter. It has non-D linkage, such asextern (C).

extern (C)void dry(int x,int y, ...);// C-style Variadic Functionvoid spin(){    dry(3, 4);// ok, no variadic arguments    dry(3, 4, 6.8);// ok, one variadic argument//dry(2);       // error, no argument for parameter y}

There must be at least one non-variadic parameter declared.

extern (C)int def(...);// error, must have at least one parameter

C-style variadic functions match the C calling convention for variadic functions, and can call C Standard library functions likeprintf.

extern (C)int printf(const(char)*, ...);void main(){    printf("hello world\n");}

C-style variadic functions cannot be marked as@safe.

To access the variadic arguments, import the standard library modulecore.stdc.stdarg.

import core.stdc.stdarg;import std.stdio;extern (C)void rinse(int x,int y, ...){    va_list args;    va_start(args, y);// y is the last named parameterint z;    va_arg(args, z);// z is set to 5    va_end(args);    writeln(z);}void main(){    rinse(3, 4, 5);// first variadic argument is 5}

D-style Variadic Functions

D-style variadic functions have D linkage and... as the last parameter.

... can be the only parameter.

If there are parameters preceding the... parameter, there must be a comma separating them from the....

Note: If the comma is omitted, it is aTypesafe Variadic Function.
int abc(char c, ...);// one required parameter: cint def(...);// no required parametersint ghi(int i ...);// a typesafe variadic function//int boo(, ...);       // error

Two hidden arguments are passed to the function:

_argptr is a pointer to the first of the variadic arguments. To access the variadic arguments, importcore.vararg. Use_argptr in conjunction withva_arg:

import core.vararg;import std.stdio;@systemvoid foo(int x,int y, ...){int z = va_arg!int(_argptr);// z is set to 5 and _argptr is advanced// to the next argument    writeln(z);// 5}void main(){    foo(3, 4, 5);// first variadic argument is 5}

_arguments gives the number of arguments and thetypeid of each, enabling type safety to be checked at run time.

import std.stdio;void main(){    Foo f =new Foo();    Bar b =new Bar();    writefln("%s", f);    printargs(1, 2, 3L, 4.5, f, b);}class Foo {int x = 3; }class Bar {long y = 4; }import core.vararg;@systemvoid printargs(int x, ...){    writefln("%d arguments", _arguments.length);for (int i = 0; i < _arguments.length; i++)    {        writeln(_arguments[i]);if (_arguments[i] ==typeid(int))        {int j = va_arg!(int)(_argptr);            writefln("\t%d", j);        }elseif (_arguments[i] ==typeid(long))        {long j = va_arg!(long)(_argptr);            writefln("\t%d", j);        }elseif (_arguments[i] ==typeid(double))        {double d = va_arg!(double)(_argptr);            writefln("\t%g", d);        }elseif (_arguments[i] ==typeid(Foo))        {            Foo f = va_arg!(Foo)(_argptr);            writefln("\t%d", f.x);        }elseif (_arguments[i] ==typeid(Bar))        {            Bar b = va_arg!(Bar)(_argptr);            writefln("\t%d", b.y);        }elseassert(0);    }}
which prints:
0x00870FE05 argumentsint        2long        3double        4.5Foo        3Bar        4

D-style variadic functions cannot be marked as@safe (if they callva_arg).

Typesafe Variadic Functions

A typesafe variadic function has D linkage and a variadic parameter, which is typically an array followed by.... The variadic parameter must be the last one. When passing component arguments (e.g. array elements), the variadic parameter is implicitly constructed from the given arguments.

A dynamic array variadic parameter accepts either a dynamic array argument or any number of arguments, each of which must implicitly convert to the array element type:

int sum(int[] ar ...)// typesafe variadic function{int s;foreach (int x; ar)        s += x;return s;}void main(){assert(sum(1, 2, 3) == 6);assert(sum() == 0);int[3] ii = [4, 5, 6];assert(sum(ii) == 15);}

A static array variadic parameter accepts either a static array argument or a fixed number of arguments which matches the array dimension:

int sum(int[3] ar ...)// typesafe variadic function{int s;foreach (int x; ar)        s += x;return s;}void main(){int i;//i = sum(2, 3);    // error, need 3 values for array    i = sum(1, 2, 3);assert(i == 6);int[3] ii = [4, 5, 6];    i = sum(ii);assert(i == 15);int[] jj = ii;//i = sum(jj); // error, type mismatch}
Deprecated:
For class objects:
int tesla(int x, C c ...){return x + c.x;}class C{int x;    string s;this(int x, string s)    {this.x = x;this.s = s;    }}void edison(){    C g =new C(3,"abc");    tesla(1, c);// ok, since c is an instance of C    tesla(1, 4,"def");// ok    tesla(1, 5);// error, no matching constructor for C}

The lifetime of the variadic class object or array instance ends at the end of the function.

C orville(C c ...){return c;// error, c instance contents invalid after return}int[] wilbur(int[] a ...){return a;// error, array contents invalid after returnreturn a[0..1];// error, array contents invalid after returnreturn a.dup;// ok, since copy is made}
Implementation Defined: the variadic object or array instance may be constructed on the stack.

For other types, the variadic parameter matches exactly one argument, which is passed by value.

int neil(int i ...){return i;}void buzz(){    neil();// error, missing argument    neil(3);// returns 3    neil(3, 4);// error, too many argumentsint[] x;    neil(x);// error, type mismatch}

Lazy Variadic Functions

If the variadic parameter of a function is an array of delegates with no parameters, then each of the arguments whose type does not match that of the delegate is converted to a delegate of that type.

void hal(scopeintdelegate()[] dgs ...);void dave(){intdelegate() dg;    hal(1, 3+x, dg,cast(intdelegate())null);// (1)    hal( {return 1; }, {return 3+x; }, dg,null );// same as (1)}

The variadic delegate array differs from using a lazy variadic array. With the latter each array element access would evaluate every array element. With the former, only the element being accessed would be evaluated.

import std.stdio;void main(){int x;    ming(++x, ++x);int y;    flash(++y, ++y);}// lazy variadic arrayvoid ming(lazyint[] arr...){    writeln(arr[0]);// 1    writeln(arr[1]);// 4}// variadic delegate arrayvoid flash(scopeintdelegate()[] arr ...){    writeln(arr[0]());// 1    writeln(arr[1]());// 2}
Best Practices: Usescope when declaring the array of delegates parameter. This will prevent a closure being generated for the delegate, asscope means the delegate will not escape the function.

Hidden Parameters

Ref Scope Return Cases

Definitions

Definitions
TermDescription
Itype that contains no indirections
Ptype that contains indirections
Xtype that may or may not contain indirections
pparameter of type P
iparameter of type I
refref orout parameter
returnedreturned via thereturn statement
escapedstored in a global or other memory not in the function’s stack frame

Classification

A parameter must be in one of the following states:

Classification
TermDescription
Nonep may be returned or escaped
ReturnScopep may be returned but not escaped
Scopep may be neither returned nor escaped
Refp may be returned or escaped,ref may not be returned nor escaped
ReturnRefp may be returned or escaped,ref may be returned but not escaped
RefScopep may be neither returned nor escaped,ref may not be returned nor escaped
ReturnRef-Scopep may be neither returned nor escaped,ref may be returned but not escaped
Ref-ReturnScopep may be returned but not escaped,ref may not be returned nor escaped
ReturnRef-ReturnScopep may be returned but not escaped,ref may be returned but not escaped. This isn't expressible with the current syntax and so is not allowed.

Mapping Syntax Onto Classification

The juxtaposition ofreturn immediately precedingscope means ReturnScope. Otherwise,return andref in any position means ReturnRef.

Mapping
ExampleClassificationComments
X foo(P p) None
X foo(scope P p) Scope
P foo(return scope P p) ReturnScope
I foo(return scope P p) Scope Thereturn is dropped because the return typeI contains no pointers.
P foo(return P p) ReturnScope Makes no sense to havereturn withoutscope.
I foo(return P p) Scope Thereturn is dropped because the return typeI contains no pointers.
X foo(ref P p) Ref
X foo(ref scope P p) RefScope
P foo(ref return scope P p) Ref-ReturnScope
P foo(return ref scope P p) ReturnRef-Scope
I foo(ref return scope P p) RefScope
P foo(ref return P p) ReturnRef
I foo(ref return P p) Ref
ref X foo(P p) None
ref X foo(scope P p) Scope
ref X foo(return scope P p) ReturnScope
ref X foo(return P p) ReturnScope Makes no sense to havereturn withoutscope.
ref X foo(ref P p) Ref
ref X foo(ref scope P p) RefScope
ref X foo(ref return scope P p) Ref-ReturnScope
ref X foo(return ref scope P p) ReturnRef-Scope
ref X foo(ref return P p) ReturnRef
X foo(I i) None
X foo(scope I i) None
X foo(return scope I i) None
X foo(return I i) None
X foo(ref I i) Ref
X foo(ref scope I i) Ref
X foo(ref return scope I i) Ref
P foo(ref return I i) ReturnRef
I foo(ref return I i) Ref
ref X foo(I i) None
ref X foo(scope I i) None
ref X foo(return scope I i) None
ref X foo(return I i) None
ref X foo(ref I i) Ref
ref X foo(ref scope I i) Ref
ref X foo(ref return scope I i) ReturnRef
ref X foo(ref return I i) ReturnRef

Member Functions

Member functions are rewritten as if thethis parameter is the first parameter of a non-member function,

struct S {    X foo();}

is treated as:

X foo(ref S);

and:

class C {    X foo()}

is treated as:

X foo(P)

P and ref

The rules account for switching betweenref and P, such as:

int* foo(returnrefint i) {return &i; }refint foo(int* p) {return *p; }

Covariance

Covariance means a parameter with restrictions can be converted to a parameter with fewer restrictions. This is deducible from the description of each state.

Note:ref is not covariant with non-ref, so those entries are omitted from the table for simplicity.
Covariance
From\To None ReturnScopeScope
None
ReturnScope
Scope
Ref Covariance
From\To RefReturnRefRefScopeReturnRef-ScopeRef-ReturnScope
Ref
ReturnRef
RefScope
ReturnRef-Scope
Ref-ReturnScope

For example,scope matches all non-ref parameters, andref scope matches all ref parameters.

Local Variables

Local variables are declared within the scope of a function. Function parameters are included.

A local variable cannot be read without first assigning it a value.

Implementation Defined: The implementation may not always be able to detect these cases.

The address of or reference to a local non-static variable cannot be returned from the function.

A local variable and a label in the same function cannot have the same name.

A local variable cannot hide another local variable in the same function.

Rationale: whenever this is done it often is a bug or at least looks like a bug.
refdouble func(int x){int x;// error, hides previous definition of xdouble y;    {char y;// error, hides previous definition of yint z;    }    {wchar z;// Ok, previous z is out of scope    }  z:// error, z is a local variable and a labelreturn y;// error, returning ref to local}

Local Static Variables

Local variables in functions declared asstatic,shared static or__gshared are statically allocated rather than being allocated on the stack. The lifetime of__gshared andshared static variables begins when the function is first executed and ends when the program ends. The lifetime ofstatic variables begins when the function is first executed within the thread and ends when that thread terminates.

import std.stdio : writeln;void foo(){staticint n;if (++n == 100)        writeln("called 100 times");}

The initializer for a static variable must be evaluatable at compile time. There are no static constructors or static destructors for static local variables.

Although static variable name visibility follows the usual scoping rules, the names of them must be unique within a particular function.

void main(){    {staticint x; }    {staticint x; }// error    {int i; }    {int i; }// ok}

Nested Functions

Functions may be nested within other functions:

int bar(int a){int foo(int b)    {int abc() {return 1; }return b + abc();    }return foo(a);}void test(){int i = bar(3);// i is assigned 4}

Nested functions can be accessed only if the name is in scope.

void foo(){void A()    {        B();// error, B() is forward referenced        C();// error, C undefined    }void B()    {        A();// ok, in scopevoid C()        {void D()            {                A();// ok                B();// ok                C();// ok                D();// ok            }        }    }    A();// ok    B();// ok    C();// error, C undefined}
and:
int bar(int a){int foo(int b) {return b + 1; }int abc(int b) {return foo(b); }// okreturn foo(a);}void test(){int i = bar(3);// okint j = bar.foo(3);// error, bar.foo not visible}

Nested functions have access to the variables and other symbols defined by the lexically enclosing function. This access includes both the ability to read and write them.

int bar(int a){int c = 3;int foo(int b)    {        b += c;// 4 is added to b        c++;// bar.c is now 5return b + c;// 12 is returned    }    c = 4;int i = foo(a);// i is set to 12return i + c;// returns 17}void test(){int i = bar(3);// i is assigned 17}

This access can span multiple nesting levels:

int bar(int a){int c = 3;int foo(int b)    {int abc()        {return c;// access bar.c        }return b + c + abc();    }return foo(3);}

Static nested functions cannot access any stack variables of any lexically enclosing function, but can access static variables. This is analogous to how static member functions behave.

int bar(int a){int c;staticint d;staticint foo(int b)    {        b = d;// ok        b = c;// error, foo() cannot access frame of bar()return b + 1;    }return foo(a);}

Functions can be nested within member functions:

struct Foo{int a;int bar()    {int c;int foo()        {return c + a;        }return 0;    }}

Nested functions always have the D function linkage type.

Declaration Order

Unlike module level declarations, declarations within function scope are processed in order. This means that two nested functions cannot mutually call each other:

void test(){void foo() { bar(); }// error, bar not definedvoid bar() { foo(); }// ok}

There are several workarounds for this limitation:

Nested functions cannot be overloaded.

Function Pointers, Delegates and Closures

Function Pointers

A function pointer is declared with thefunction keyword:

void f(int);voidfunction(int) fp = &f;// fp is a pointer to a function taking an int

A function pointer can point to a static nested function:

intfunction() fp;// fp is a pointer to a function returning an intvoid test(){staticint a = 7;staticint foo() {return a + 3; }    fp = &foo;}void main(){assert(!fp);    test();int i = fp();assert(i == 10);}
Implementation Defined: Two functions with identical bodies, or two functions that compile to identical assembly code, are not guaranteed to have distinct function pointer values. The implementation may merge functions bodies into one if they compile to identical code.
int abc(int x)   {return x + 1; }uint def(uint y) {return y + 1; }intfunction(int)   fp1 = &abc;uintfunction(uint) fp2 = &def;// Do not rely on fp1 and fp2 being different values; the compiler may merge// them.

Delegates & Closures

Adelegate can be set to a non-staticnested function:

intdelegate() dg;void test(){int a = 7;int foo() {return a + 3; }    dg = &foo;int i = dg();// i is set to 10}void main(){    test();int i = dg();// ok, test.a is in a closure and still existsassert(i == 10);}

The stack variables referenced by a nested function are still valid even after the function exits (NOTE this is different from D 1.0). This combining of the environment and the function is called adynamic closure.

Those referenced stack variables that make up the closure are allocated on the GC heap, unless:

@nogc:void f(scopeintdelegate());void g(intdelegate());void main(){int i;int h() {return i; }    h();// OKscope x = &h;// OK    x();// OK//auto y = &h; // error, can't allocate closure in @nogc function    f(&h);// OK//g(&h); // error// delegate literals    f(() => i);// OKscope d = () => i;// OK    d = () => i + 1;// OK    f(d);//g(() => i); // error, can't allocate closure in @nogc function}
Note: Returning addresses of stack variables, however, is not a closure and is an error.

Method Delegates

Delegates to non-static nested functions contain two pieces of data: the pointer to the stack frame of the lexically enclosing function (called thecontext pointer) and the address of the function. This is analogous to struct/class non-static member function delegates consisting of athis pointer and the address of the member function. Both forms of delegates are indistinguishable, and are the same type.

A delegate can be set to a particular object and method using&obj.method:

struct Foo{int a;int get() {return a; }}int add1(intdelegate() dg){return dg() + 1;}void main(){    Foo f = {7};intdelegate() dg = &f.get;// bind to an instance of Foo and a methodint i = add1(dg);assert(i == 8);int x = 27;int abc() {return x; }    i = add1(&abc);assert(i == 28);}

Initialization

Function pointers are zero-initialized by default. They can be initialized to the address of any function (including a function literal). Initialization with the address of a function that requires a context pointer is not allowed in @safe functions.

Undefined Behavior: Calling a function pointer that was set to point to a function that requires a context pointer.
struct S{staticint sfunc();int member();// has hidden `this` reference parameter}@safevoid sun(){intfunction() fp = &S.sfunc;    fp();// Ok    fp = &S.member;// error}@systemvoid moon(){intfunction() fp = &S.member;// Ok because @system    fp();// undefined behavior}

Delegates are zero-initialized by default. They can be initialized by taking the address of a non-static member function, but a context pointer must be supplied. They can be initialized by taking the address of a non-static nested function or function literal, where the context pointer will be set to point to the stack frame, closure, ornull.

Delegates cannot be initialized by taking the address of a global function, a static member function, or a static nested function.

struct S{staticint sfunc();int member() {return 1; }}void main(){    S s;intdelegate() dg = &s.member;// Ok, s supplies context pointerassert(dg() == 1);//dg = &S.sfunc;  // error//dg = &S.member; // errorint moon() {return 2; }    dg = &moon;// Okassert(dg() == 2);staticint mars() {return 3; }//dg = &mars;     // error    dg = () {return 4; };// Okassert(dg() == 4);}

The last assignment uses aFunctionLiteral, whichis inferred as a delegate.

Note: Function pointers can be passed to functions taking a delegate argument by passing them through thestd.functional.toDelegate template, which converts any callable to a delegate with anull context pointer.

Anonymous Functions and Anonymous Delegates

SeeFunctionLiterals.

main() Function

For console programs,main() serves as the entry point. It gets called after all themodule initializers are run, and after anyunittests are run. After it returns, all the module destructors are run.main() must be declared as follows:

MainFunction:MainReturnDeclmain()FunctionBodyMainReturnDeclmain(string[]Identifier)FunctionBody
MainReturnDecl:voidintnoreturnauto

If thestring[] parameter is declared, the parameter will hold arguments passed to the program by the OS. The first argument is typically the executable name, followed by any command-line arguments.

Note: The runtime can remove any arguments prefixed--DRT-.
Note: The aforementioned return / parameter types may be annotated withconst,immutable. They may also be replaced byenum's with matching base types.

The main function must have D linkage.

Attributes may be added as needed, e.g.@safe,@nogc,nothrow, etc.

extern(C) main() Function

Programs may define anextern(C) main function as an alternative to the standardentry point. This form is required forBetterC programs.

A Cmain function must be declared as follows:

CMainFunction:extern (C)MainReturnDeclmain(CmainParametersopt)BlockStatement
CmainParameters:intIdentifier,char**IdentifierintIdentifier,char**Identifier,char**Identifier

When defined, the first two parameters denote a C-style array (length + pointer) that holds the arguments passed to the program by the OS. The third parameter is a POSIX extension calledenviron and holds information about the current environment variables.

Note: The exemption for storage classes /enum's defined for a Dmain function also applies to Cmain functions.

This function takes the place of the C main function and is executed immediately without any setup or teardown associated with a Dmain function. Programs reliant on module constructors, module destructors, or unittests need to manually perform (de)initialization using the appropriateruntime functions.

Implementation Defined: Other system-specific entry points may exist, such asWinMain andDllMain on Windows systems.
Note: Programs targeting platforms which require a different signature formain can use a function withexplicit mangling:
pragma(mangle,"main")int myMain(int a,int b,int c){return 0;}

Function Templates

Functions can have compile time arguments in the form of a template. Seefunction templates.

Compile Time Function Execution (CTFE)

In contexts where a compile time value is required, functions can be used to compute those values. This is calledCompile Time Function Execution, orCTFE.

These contexts are:

enum eval(alias arg) = arg;int square(int i){return i * i;}void main(){import std.stdio;static j = square(3);// CTFE    writeln(j);assert(square(4) == 16);// run timestaticassert(square(3) == 9);// CTFE    writeln(eval!(square(5)));// CTFE}

The function must have aFunctionBody.

CTFE is subject to the following restrictions:

  1. Expressions may not reference any mutable static variables.
  2. AsmStatements are not permitted
  3. Non-portable casts (e.g., fromint[] tofloat[]), including casts which depend on endianness, are not permitted. Casts between signed and unsigned types are permitted.
  4. Reinterpretation of overlapped fields in a union is not permitted.
  5. Undefined behavior must not occur.

Pointers are permitted in CTFE, provided they are used safely:

The above restrictions apply only to expressions which are actually evaluated. For example:

staticint y = 0;int countTen(int x){if (x > 10)        ++y;// access static variablereturn x;}staticassert(countTen(6) == 6);// OKstaticassert(countTen(12) == 12);// invalid, modifies y.

The__ctfe boolean pseudo-variable evaluates totrue during CTFE butfalse otherwise.

Note:__ctfe can be used to provide an alternative execution path to avoid operations which are forbidden in CTFE. Every usage of__ctfe is statically evaluated and has no run-time cost.

Non-recoverable errors (such asassert failures) are illegal.

Implementation Defined: Executing functions via CTFE can take considerably longer than executing it at run time. If the function goes into an infinite loop, it may cause the compiler to hang.
Implementation Defined: Functions executed via CTFE can give different results from run time when implementation-defined behavior occurs.

String Mixins and Compile Time Function Execution

All functions that execute in CTFE must also be executable at run time. The compile time evaluation of a function does the equivalent of running the function at run time. The semantics of a function cannot depend on compile time values of the function. For example:

int foo(string s){returnmixin(s);}constint x = foo("1");
is illegal, because the runtime code forfoo cannot be generated.
Best Practices: A function template, wheres is a template argument, would be the appropriate method to implement this sort of thing.

No-GC Functions

No-GC functions are functions marked with the@nogc attribute. Those functions do not allocate memory on the GC heap. These operations are not allowed in No-GC functions:

  1. constructing an array on the heap
  2. resizing an array by writing to its.length property
  3. array concatenation
  4. array appending
  5. constructing an associative array
  6. indexing an associative array
    Rationale: Indexing may throw aRangeError if the specified key is not present.
  7. allocating an object withnew on the heap
    Note:new declarations ofclass types in function scopes are compatible with@nogc if used to initialize ascope variable, as they result in allocations on the stack.
  8. calling functions that are not@nogc, unless the call is in aConditionalStatement controlled by aDebugCondition
@nogcvoid foo(){auto a = ['a'];// (1) error, allocates    a.length = 1;// (2) error, array resizing allocates    a = a ~ a;// (3) error, arrays concatenation allocates    a ~= 'c';// (4) error, appending to arrays allocatesauto aa = ["x":1];// (5) error, allocates    aa["abc"];// (6) error, indexing may allocate and throwsauto p =newint;// (7) error, operator new allocatesscopeauto p =new GenericClass();// (7) Ok    bar();// (8) error, bar() may allocatedebug bar();// (8) Ok}void bar() { }

No-GC functions can only use a closure if it isscope - seeDelegates & Closures.

@nogcintdelegate() foo(){int n;// error, variable n cannot be allocated on heapreturn (){return n; }// since `n` escapes `foo()`, a closure is required}

@nogc affects the type of the function. A@nogc function is covariant with a non-@nogc function.

voidfunction() fp;voidfunction() @nogc gp;// pointer to @nogc functionvoid foo();@nogcvoid bar();void test(){    fp = &foo;// ok    fp = &bar;// ok, it's covariant    gp = &foo;// error, not contravariant    gp = &bar;// ok}
Best Practices: Since a function marked@nogc will not do any GC allocations, that implies it will not cause any GC collections to run. However, another thread may still allocate with the GC and trigger a collection. The recommended way to prevent GC collections from being run is to callcore.memory.GC.disable() instead. This will stop collections from being run in any thread until a corresponding call tocore.memory.GC.enable() is run. GC allocations can still be performed whenGC.disable() is in effect.

Function Safety

Safe Functions

Safe functions are marked with the@safe attribute.@safe can be inferred, seeFunction Attribute Inference.

Safe functions havesafe interfaces. An implementation must enforce this by restricting the function's body to operations that are known to be safe, except for calls to@trusted functions.

The following restrictions are enforced by the compiler in safe functions:

Note: When indexing or slicing an array, an out of bounds access will cause a runtime error.

Functions nested inside safe functions default to being safe functions.

Safe functions are covariant with trusted or system functions.

Best Practices: Mark as many functions@safe as practical.

Safe External Functions

External functions don't have a function body visible to the compiler:

@safeextern (C)void play();
and so safety cannot be verified automatically.
Best Practices: Explicitly set an attribute for external functions rather than relying on default settings.

Trusted Functions

Trusted functions are marked with the@trusted attribute.

Likesafe functions, trusted functions havesafe interfaces. Unlike safe functions, this is not enforced by restrictions on the function body. Instead, it is the responsibility of the programmer to ensure that the interface of a trusted function is safe.

Example:

immutable(int)* f(int* p) @trusted{version (none) p[2] = 13;// Invalid. p[2] is out of bounds. This line would exhibit undefined// behavior.version (none) p[1] = 13;// Invalid. In this program, p[1] happens to be in-bounds, so the// line would not exhibit undefined behavior, but a trusted function// is not allowed to rely on this.version (none)returncast(immutable) p;// Invalid. @safe code still has mutable access and could trigger// undefined behavior by overwriting the value later on.int* p2 =newint;    *p2 = 42;returncast(immutable) p2;// Valid. After f returns, no mutable aliases of p2 can exist.}void main() @safe{int[2] a = [10, 20];int* mp = &a[0];immutable(int)* ip = f(mp);assert(a[1] == 20);// Guaranteed. f cannot access a[1].assert(ip !is mp);// Guaranteed. f cannot introduce unsafe aliasing.}

Trusted functions may call safe, trusted, or system functions.

Trusted functions are covariant with safe or system functions.

Best Practices: Trusted functions should be kept small so that they are easier to manually verify.

System Functions

System functions are functions not marked with@safe or@trusted and are not nested inside@safe functions. System functions may be marked with the@system attribute. A function being system does not mean it actually is unsafe, it just means that its safety must be manually verified.

System functions arenot covariant with trusted or safe functions.

System functions can call safe and trusted functions.

Best Practices: When in doubt, markextern (C) andextern (C++) functions as@system when their implementations are not in D, as the D compiler will be unable to check them. Most of them are@safe, but will need to be manually checked.
Best Practices: The number and size of system functions should be minimized. This minimizes the work necessary to manually check for safety.

Safe Interfaces

When a function call's arguments,any context and accessible globals each havesafe values withsafe aliasing, that function has a safe interface when:

  1. it cannot exhibitundefined behavior, and
  2. it cannot create unsafe values that are accessible from@safe code (e.g., via return values, global variables, orref parameters), and
  3. it cannot introduce unsafe aliasing that is accessible from@safe code.

Functions that meet these requirements may be@safe or@trusted. Function that do not meet these requirements can only be@system.

Examples:

Safe Values

A variable or field marked as@system does not hold a safe value, regardless of its type.

For abool, only 0 and 1 are safe values.

For all otherbasic data types, all possible bit patterns are safe.

A pointer is a safe value when it is one of:

  1. null -see below
  2. it points to a memory object that is live and the pointed to value in that memory object is safe.

Examples:

int* n =null;/* n is safe because dereferencing null must either crash    or abort. */int* x =cast(int*) 0xDEADBEEF;/* x is (most likely) unsafe because it    is not a valid pointer and cannot be dereferenced. */import core.stdc.stdlib: malloc, free;int* p1 =cast(int*) malloc(int.sizeof);/* p1 is safe because the    pointer is valid and *p1 is safe regardless of its actual value. */free(p1);/* This makes p1 unsafe. */int** p2 = &p1;/* While it can be dereferenced, p2 is unsafe because p1    is unsafe. */p1 =null;/* This makes p1 and p2 safe. */

A dynamic array is safe when:

  1. its pointer is safe, and
  2. its length is in-bounds with the corresponding memory object, and
  3. all its elements are safe.

Examples:

int[] f() @system{bool b =true;/* b is initialized safe */    *(cast(ubyte*) &b) = 0xAA;/* b is now unsafe because it's not 0 or 1 */int[3] a;int[] d1 = a[0 .. 3];/* d1 is safe. */int[] d2 = a.ptr[0 .. 4];/* d2 is unsafe because it goes beyond a's        bounds. */int*[] d3 = [cast(int*) 0xDEADBEEF];/* d3 is unsafe because the        element is unsafe. */return d1;/* Up to here, d1 was safe, but its pointer becomes        invalid when the function returns, so the returned dynamic array        is unsafe. */}

A static array is safe when all its elements are safe. Regardless of the element type, a static array with length zero is always safe.

An associative array is safe when all its keys and elements are safe.

A struct/union instance is safe when:

  1. the values of its accessible fields are safe, and
  2. it does not introduceunsafe aliasing with unions.

Examples:

void fun(){struct S {int* p; }    S s1 = S(newint);/* s1 is safe. */    S s2 = S(cast(int*) 0xDEADBEEF);/* s2 is unsafe, because s2.p is        unsafe. */union U {int* p; size_t x; }    U u = U(newint);/* Even though both u.p and u.x are safe, u is unsafe        because of unsafe aliasing. */}

A class reference is safe when it isnull or:

  1. it refers to a valid class instance of the class type or a type derived from the class type, and
  2. the values of the instance's accessible fields are safe, and
  3. it does not introduce unsafe aliasing with unions.

A function pointer is safe when it isnull or it refers to a valid function that has the same or a covariant signature.

Adelegate is safe when:

  1. its.funcptr property isnull or refers to a function that matches or is covariant with the delegate type, and
  2. its.ptr property isnull or refers to a memory object that is in a form expected by the function.

Null Dereferences

When generating@safe code, a compliant implementation:

Safe Aliasing

When one memory location is accessible with two different types, that aliasing is considered safe if:

  1. both types areconst orimmutable; or
  2. one of the types is mutable while the other is aconst-qualifiedbasic data type; or
  3. both types are mutable basic data types; or
  4. one of the types is a static array type with length zero; or
  5. one of the types is a static array type with non-zero length, and aliasing of the array's element type and the other type is safe; or
  6. both types are pointer types, and aliasing of the target types is safe, and the target types have the same size.

All other cases of aliasing are considered unsafe.

Note: Safe aliasing may be exposed to functions withsafe interfaces without affecting their guaranteed safety. Unsafe aliasing does not guarantee safety.
Note: Safe aliasing does not imply that all aliased views of the data havesafe values. Those must be examined separately for safety.

Examples:

void f1(refubyte x,reffloat y) @safe { x = 0; y =float.init; }union U1 {ubyte x;float y; }// safe aliasingvoid test1(){    U1 u1;    f1(u1.x, u1.y);// Ok}void f2(refint* x,refint y) @trusted { x =newint; y = 0xDEADBEEF; }union U2 {int* x;int y; }// unsafe aliasingvoid test2(){    U2 u2;version (none) f1(u2.x, u2.y);// not safe}

Function Attribute Inference

FunctionLiterals,Auto Functions,Auto Ref Functions,nested functions andfunction templates, since their function bodies are always present, infer the following attributes unless specifically overridden:

Attribute inference is not done for other functions, even if the function body is present.

The inference is done by determining if the function body follows the rules of the particular attribute.

Cyclic functions (i.e. functions that wind up directly or indirectly calling themselves) are inferred as being impure, throwing, and@system.

If a function attempts to test itself for those attributes, then the function is inferred as not having those attributes.

Rationale: Function attribute inference greatly reduces the need for the user to add attributes to functions, especially for templates.

Uniform Function Call Syntax (UFCS)

A free function can be called like a member function when both:

The object expression can be any type. This is called aUFCS function call.

void sun(T,int);void moon(T t){    t.sun(1);// If `T` does not have a member function `sun`,// `t.sun(1)` is interpreted as if it were written `sun(t, 1)`}
Rationale: This provides a way to add external functions to a class as if they were publicfinal member functions. This enables minimizing the number of functions in a class to only the essentials that are needed to take care of the object's private state, without the temptation to add a kitchen-sink's worth of member functions. It also enables function chaining and component programming.
This general idea has different names in other programming languages. The following is a short list:

A more complex example:

stdin.byLine(KeepTerminator.yes)    .map!(a => a.idup)    .array    .sort    .copy(stdout.lockingTextWriter());

is the equivalent of:

copy(sort(array(map!(a => a.idup)(byLine(stdin, KeepTerminator.yes)))), lockingTextWriter(stdout));

UFCS works with@property functions:

@property prop(X thisObj);@property prop(X thisObj,int value);X obj;obj.prop;// if X does not have member prop, reinterpret as prop(obj);obj.prop = 1;// similarly, reinterpret as prop(obj, 1);

Functions declared in a local scope are not found when searching for a matching UFCS function. Neither are other local symbols, although local imports are searched:

module a;void foo(X);alias boo = foo;void main(){void bar(X);// bar declared in local scopeimport b : baz;// void baz(X);    X obj;    obj.foo();// OK, calls a.foo;//obj.bar();  // NG, UFCS does not see nested functions    obj.baz();// OK, calls b.baz, because it is declared at the// top level scope of module bimport b : boo = baz;    obj.boo();// OK, calls aliased b.baz instead of a.boo (== a.foo),// because the declared alias name 'boo' in local scope// overrides module scope name}

Member functions are not found when searching for a matching UFCS function.

class C{void mfoo(X);// member functionstaticvoid sbar(X);// static member functionimport b : ibaz = baz;// void baz(X);void test()    {        X obj;//obj.mfoo();  // NG, UFCS does not see member functions//obj.sbar();  // NG, UFCS does not see static member functions        obj.ibaz();// OK, ibaz is an alias of baz which is declared at//     the top level scope of module b    }}

Otherwise, UFCS function lookup proceeds normally.

Rationale: Local function symbols are not considered by UFCS to avoid unexpected name conflicts. See below for problematic examples.
int front(int[] arr) {return arr[0]; }void main(){int[] a = [1,2,3];auto x = a.front();// call .front by UFCSauto front = x;// front is now a variableauto y = a.front();// Error, front is not a function}class C{int[] arr;int front()    {return arr.front();// Error, C.front is not callable// using argument types (int[])    }}
Type Qualifiers
Operator Overloading
)
Copyright © 1999-2025 by theD Language Foundation | Page generated byDdoc on Fri Oct 10 22:16:57 2025

[8]ページ先頭

©2009-2025 Movatter.jp