$(DDOC $(DDOC_BLANKLINE )
$(DDOC_BLANKLINE )
$(SPEC_S Statements,
$(DDOC_BLANKLINE )
$(HEADERNAV_TOC $(HEADERNAV_ITEM scope-statement, Scope Statements)
$(HEADERNAV_ITEM scope-block-statement, Scope Block Statements)
$(HEADERNAV_ITEM labeled-statement, Labeled Statements)
$(HEADERNAV_ITEM block-statement, Block Statement)
$(HEADERNAV_ITEM expression-statement, Expression Statement)
$(HEADERNAV_ITEM declaration-statement, Declaration Statement)
$(HEADERNAV_ITEM if-statement, If Statement)
$(HEADERNAV_ITEM while-statement, While Statement)
$(HEADERNAV_ITEM do-statement, Do Statement)
$(HEADERNAV_ITEM for-statement, For Statement)
$(HEADERNAV_SUBITEMS foreach-statement, Foreach Statement,
$(HEADERNAV_ITEM foreach_over_arrays, Foreach over Arrays)
$(HEADERNAV_ITEM foreach_over_arrays_of_characters, Foreach over Arrays of Characters)
$(HEADERNAV_ITEM foreach_over_associative_arrays, Foreach over Associative Arrays)
$(HEADERNAV_ITEM foreach_over_struct_and_classes, Foreach over Structs and Classes with opApply
)
$(HEADERNAV_ITEM foreach-with-ranges, Foreach over Structs and Classes with Ranges)
$(HEADERNAV_ITEM foreach_over_delegates, Foreach over Delegates)
$(HEADERNAV_ITEM foreach_over_tuples, Foreach over Sequences)
$(HEADERNAV_ITEM foreach_ref_parameters, Foreach Ref Parameters)
$(HEADERNAV_ITEM foreach_restrictions, Foreach Restrictions)
$(HEADERNAV_ITEM foreach-range-statement, Foreach Range Statement)
)
$(HEADERNAV_SUBITEMS switch-statement, Switch Statement,
$(HEADERNAV_ITEM case-range, Case Range Statement)
$(HEADERNAV_ITEM no-implicit-fallthrough, No Implicit Fall-Through)
$(HEADERNAV_ITEM string-switch, String Switch)
)
$(HEADERNAV_ITEM final-switch-statement, Final Switch Statement)
$(HEADERNAV_ITEM continue-statement, Continue Statement)
$(HEADERNAV_ITEM break-statement, Break Statement)
$(HEADERNAV_ITEM return-statement, Return Statement)
$(HEADERNAV_ITEM goto-statement, Goto Statement)
$(HEADERNAV_ITEM with-statement, With Statement)
$(HEADERNAV_ITEM synchronized-statement, Synchronized Statement)
$(HEADERNAV_ITEM try-statement, Try Statement)
$(HEADERNAV_SUBITEMS scope-guard-statement, Scope Guard Statement,
$(HEADERNAV_ITEM catching_cpp_class_objects, Catching C++ Class Objects)
)
$(HEADERNAV_ITEM asm, Asm Statement)
$(HEADERNAV_ITEM pragma-statement, Pragma Statement)
$(HEADERNAV_ITEM mixin-statement, Mixin Statement)
)
$(DDOC_BLANKLINE )
$(P The order of execution within a function is controlled by $(GLINK Statement)s.
A function's body consists of a sequence of zero or more $(I Statement)s.
Execution occurs in lexical order, though certain statements may have deferred effects.
A $(I Statement) has no value; it is executed for its effects.
)
$(DDOC_BLANKLINE )
$(GRAMMAR $(GNAME Statement):
$(GLINK EmptyStatement)
$(GLINK NonEmptyStatement)
$(GLINK ScopeBlockStatement)
$(DDOC_BLANKLINE )
$(GNAME EmptyStatement):
$(D ;)
$(DDOC_BLANKLINE )
$(GNAME NoScopeNonEmptyStatement):
$(GLINK NonEmptyStatement)
$(GLINK BlockStatement)
$(DDOC_BLANKLINE )
$(GNAME NoScopeStatement):
$(GLINK EmptyStatement)
$(GLINK NonEmptyStatement)
$(GLINK BlockStatement)
$(DDOC_BLANKLINE )
$(GNAME NonEmptyOrScopeBlockStatement):
$(GLINK NonEmptyStatement)
$(GLINK ScopeBlockStatement)
$(DDOC_BLANKLINE )
$(GNAME NonEmptyStatement):
$(GLINK NonEmptyStatementNoCaseNoDefault)
$(GLINK CaseStatement)
$(GLINK CaseRangeStatement)
$(GLINK DefaultStatement)
$(DDOC_BLANKLINE )
$(GNAME NonEmptyStatementNoCaseNoDefault):
$(GLINK LabeledStatement)
$(GLINK ExpressionStatement)
$(GLINK DeclarationStatement)
$(GLINK IfStatement)
$(GLINK WhileStatement)
$(GLINK DoStatement)
$(GLINK ForStatement)
$(GLINK ForeachStatement)
$(GLINK SwitchStatement)
$(GLINK FinalSwitchStatement)
$(GLINK ContinueStatement)
$(GLINK BreakStatement)
$(GLINK ReturnStatement)
$(GLINK GotoStatement)
$(GLINK WithStatement)
$(GLINK SynchronizedStatement)
$(GLINK TryStatement)
$(GLINK ScopeGuardStatement)
$(GLINK AsmStatement)
$(GLINK MixinStatement)
$(GLINK ForeachRangeStatement)
$(GLINK2 pragma, PragmaStatement)
$(GLINK2 version, ConditionalStatement)
$(GLINK2 version, StaticForeachStatement)
$(GLINK2 module, ImportDeclaration)
)
$(DDOC_BLANKLINE )
$(P Any ambiguities in the grammar between $(I Statement)s and
$(GLINK2 declaration, Declaration)s are
resolved by the declarations taking precedence.
Wrapping such a statement in parentheses will
disambiguate it in favor of being a $(I Statement).
)
$(DDOC_BLANKLINE )
{ }
.
The statements are executed in lexical order,
until the end of the block is reached or
a statement transfers control elsewhere.
)
$(DDOC_BLANKLINE )
$(DDOC_BLANKLINE )
opCast!bool()
)
if the method is defined.
If the boolean is true
, the $(I ThenStatement) is transferred
to, otherwise the $(I ElseStatement) is transferred to.)
$(DDOC_BLANKLINE )
$(P The $(I ElseStatement) is associated with the innermost if
statement which does not already have an associated $(I ElseStatement).)
$(DDOC_BLANKLINE )
$(PANEL When an $(I Identifier) form of IfCondition is used, a
variable is declared with that name and initialized to the
value of the Expression.
$(UL $(LI If $(D auto) $(I Identifier) is provided, the type of the variable
is the same as Expression.
)
$(LI If $(I TypeCtors) $(I Identifier) is provided, the variable is
declared to be the type of Expression but with $(I TypeCtors) applied.
)
$(LI If the $(I BasicType) form is provided, it declares the type of the
variable as it would for a normal
$(DDSUBLINK spec/declaration, variable-declarations, variable declaration).
)
)
$(P The scope of the variable is the ThenStatement only.)
$(DDOC_BLANKLINE )
$(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD import) std.regex;
$(D_KEYWORD if) ($(D_KEYWORD auto) m = matchFirst($(D_STRING "abcdef"), $(D_STRING "b$(LPAREN)c$(RPAREN )d")))
{
writefln($(D_STRING "[%s]"), m.pre); $(D_COMMENT // prints [a]
) writefln($(D_STRING "[%s]"), m.post); $(D_COMMENT // prints [ef]
) writefln($(D_STRING "[%s]"), m[0]); $(D_COMMENT // prints [bcd]
) writefln($(D_STRING "[%s]"), m[1]); $(D_COMMENT // prints [c]
)}
$(D_KEYWORD else)
{
writeln($(D_STRING "no match"));
$(D_COMMENT //writeln$(LPAREN)m.post$(RPAREN ); // Error: undefined identifier 'm'
)}
$(D_COMMENT //writeln$(LPAREN)m.pre$(RPAREN ); // Error: undefined identifier 'm'
))
)
)
$(DDOC_BLANKLINE )
true
the ScopeStatement is executed.
After the ScopeStatement is executed, the Expression is evaluated again, and
if true
the ScopeStatement is executed again. This continues until the Expression
evaluates to false
.)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD int) i = 0;
$(D_KEYWORD while) (i < 10)
{
foo(i);
++i;
}
)
$(DDOC_BLANKLINE )
$(P If an $(D auto) $(I Identifier) is provided, it is declared and
initialized to the value and type of the Expression. Its scope
extends from when it is initialized to the end of the ScopeStatement.)
$(DDOC_BLANKLINE )
$(P If a $(I TypeCtors) $(I Identifier) is provided, it is declared
to be of the type specified by $(I TypeCtors) and is initialized with
the value of the Expression. Its scope extends from when it is
initialized to the end of the ScopeStatement.)
$(DDOC_BLANKLINE )
$(P If a $(I Declarator) is provided, it is declared and initialized
to the value of the Expression. Its scope extends from when it is
initialized to the end of the ScopeStatement.)
$(DDOC_BLANKLINE )
$(P A $(GLINK BreakStatement) will exit the loop.)
$(DDOC_BLANKLINE )
$(P A $(GLINK ContinueStatement) will transfer directly to evaluating $(I IfCondition) again.)
$(DDOC_BLANKLINE )
true
the loop is iterated
again. This continues until the Expression evaluates to false
.)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD int) i = 0;
$(D_KEYWORD do)
{
foo(i);
} $(D_KEYWORD while) (++i < 10);
)
$(DDOC_BLANKLINE )
$(P A $(GLINK BreakStatement) will exit the loop. A $(GLINK ContinueStatement)
will transfer directly to evaluating Expression again.)
$(DDOC_BLANKLINE )
true
the
ScopeStatement is executed. After execution,
$(I Increment) is executed.
Then $(I Test) is evaluated again, and if true
the
ScopeStatement is executed again. This continues until the
$(I Test) evaluates to false
.
)
$(DDOC_BLANKLINE )
$(P A $(GLINK BreakStatement) will exit the loop.
A $(GLINK ContinueStatement)
will transfer directly to the $(I Increment).
)
$(DDOC_BLANKLINE )
$(P A $(I ForStatement) creates a new scope.
If $(I Initialize) declares a variable, that variable's scope
extends through ScopeStatement. For example:
)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD for) ($(D_KEYWORD int) i = 0; i < 10; i++)
foo(i);
)
$(DDOC_BLANKLINE )
is equivalent to:
$(DDOC_BLANKLINE )
$(D_CODE {
$(D_KEYWORD int) i;
$(D_KEYWORD for) (i = 0; i < 10; i++)
foo(i);
}
)
$(DDOC_BLANKLINE )
$(P ScopeStatement cannot be an empty statement:)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD for) ($(D_KEYWORD int) i = 0; i < 10; i++)
; $(D_COMMENT // illegal
))
$(DDOC_BLANKLINE )
Use instead:
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD for) ($(D_KEYWORD int) i = 0; i < 10; i++)
{
}
)
$(DDOC_BLANKLINE )
$(P $(I Initialize) may be just $(D ;).
$(I Test) may be omitted, and if
so, it is treated as if it evaluated to true
.)
$(DDOC_BLANKLINE )
$(BEST_PRACTICE Consider replacing $(I ForStatements) with
$(DDSUBLINK spec/statement, foreach-statement, Foreach Statements) or
$(DDSUBLINK spec/statement, ForeachRangeStatement, Foreach Range Statements).
Foreach loops are easier to understand, less prone to error, and easier to refactor.
)
$(DDOC_BLANKLINE )
foreach
statement iterates a series of values.)
$(DDOC_BLANKLINE )
$(GRAMMAR $(GNAME AggregateForeach):
$(GLINK Foreach) $(D $(LPAREN)) $(GLINK ForeachTypeList) $(D ;) $(GLINK ForeachAggregate) $(D $(RPAREN ))
$(DDOC_BLANKLINE )
$(GNAME ForeachStatement):
$(GLINK AggregateForeach) $(GLINK NoScopeNonEmptyStatement)
$(DDOC_BLANKLINE )
$(GNAME Foreach):
$(D foreach)
$(D foreach_reverse)
$(DDOC_BLANKLINE )
$(GNAME ForeachTypeList):
$(GLINK ForeachType)
$(GLINK ForeachType) $(D ,) $(GSELF ForeachTypeList)
$(DDOC_BLANKLINE )
$(GNAME ForeachType):
$(GLINK ForeachTypeAttributes)$(OPT ) $(GLINK2 type, BasicType) $(GLINK2 declaration, Declarator)
$(GLINK ForeachTypeAttributes)$(OPT ) $(GLINK_LEX Identifier)
$(GLINK ForeachTypeAttributes)$(OPT ) $(D alias) $(GLINK_LEX Identifier)
$(DDOC_BLANKLINE )
$(GNAME ForeachTypeAttributes):
$(GLINK ForeachTypeAttribute)
$(GLINK ForeachTypeAttribute) $(GSELF ForeachTypeAttributes)
$(DDOC_BLANKLINE )
$(GNAME ForeachTypeAttribute):
$(D enum)
$(D ref)
$(D scope)
$(GLINK2 type, TypeCtor)
$(DDOC_BLANKLINE )
$(GNAME ForeachAggregate):
$(GLINK2 expression, Expression)
)
$(DDOC_BLANKLINE )
$(P $(I ForeachAggregate) is evaluated. It must evaluate to an expression
which is a static array, dynamic array, associative array,
struct, class, delegate, or sequence.
The NoScopeNonEmptyStatement is executed, once for each element of the
aggregate.
)
$(P The number of variables declared in $(I ForeachTypeList)
depends on the kind of aggregate. The declared variables are
set at the start of each iteration.
)
$(UL $(LI By default a single declared variable is a copy of the current element.)
$(LI If the $(I ForeachTypeAttribute) is $(D ref), that variable will
be a reference to the current element of the aggregate.)
$(LI If the $(I ForeachTypeAttribute) is $(D scope), the variable
will have $(DDSUBLINK spec/function, scope-parameters, scope
) semantics.)
)
$(P If not specified, the type of a $(I ForeachType) variable
can be inferred from the type of the $(I ForeachAggregate).
Note that auto
is not a valid $(I ForeachTypeAttribute).
The two foreach
statements below are equivalent:
)
$(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD int)[] arr = [1, 2, 3];
$(D_KEYWORD foreach) ($(D_KEYWORD int) n; arr)
writeln(n);
$(D_KEYWORD foreach) (n; arr) $(D_COMMENT // ok, n is an int
) writeln(n);
)
)
$(P The aggregate must be $(RELATIVE_LINK2 foreach_restrictions, loop invariant),
meaning that elements cannot be added or removed from it
in the NoScopeNonEmptyStatement.
)
$(DDOC_BLANKLINE )
$(P A $(GLINK BreakStatement) in the body of the foreach will exit the
loop. A $(GLINK ContinueStatement) will immediately start the
next iteration.
)
$(DDOC_BLANKLINE )
ref
).
)
$(P If there are
two variables declared, the first is said to be the $(I index)
and the second is said to be the $(I value) as above.
$(I index) cannot be declared with ref
.
It is set to the index of the array element on each iteration.
The index type can be inferred:
)
$(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD char)[] a = ['h', 'i'];
$(D_KEYWORD foreach) (i, $(D_KEYWORD char) c; a)
{
writefln($(D_STRING "a[%d] = '%c'"), i, c);
}
)
)
$(P For a dynamic array, the $(I index) type must be compatible
with size_t
.
Static arrays may use any integral type that spans the length
of the array.)
$(DDOC_BLANKLINE )
$(P For $(D foreach), the
elements for the array are iterated over starting at index 0
and continuing to the last element of the array.
For $(D foreach_reverse), the array elements are visited in the reverse
order.
)
$(DDOC_BLANKLINE )
char
, wchar
, or dchar
arrays:
)
$(DDOC_BLANKLINE )
$(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD foreach) ($(D_KEYWORD char) c; $(D_STRING "ab"))
{
writefln($(D_STRING "'%s'"), c);
}
$(D_KEYWORD foreach) ($(D_KEYWORD wchar) w; $(D_STRING "xy"))
{
writefln($(D_STRING "'%s'"), w);
}
)
)
$(DDOC_BLANKLINE )
$(P which would print:
)
$(DDOC_BLANKLINE )
$(CONSOLE 'a'
'b'
'x'
'y'
)
$(DDOC_BLANKLINE )
ref
,
and it is set to be the index of the array element.)
$(DDOC_BLANKLINE )
$(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_COMMENT // index type is string, value type is double
)$(D_KEYWORD double)[string] aa = [$(D_STRING "pi"):3.14, $(D_STRING "e"):2.72];
$(D_KEYWORD foreach) (string s, $(D_KEYWORD double) d; aa)
{
writefln($(D_STRING "aa['%s'] = %g"), s, d);
}
)
)
$(DDOC_BLANKLINE )
$(P The order in which the elements of the
array are iterated over is unspecified for $(D foreach).
This is why $(D foreach_reverse) for associative arrays is illegal.)
$(DDOC_BLANKLINE )
opApply
)foreach_reverse
behavior is defined by the special
$(LEGACY_LNAME2 opApplyReverse, op-apply-reverse, $(D opApplyReverse)) member function.
These functions must each have the signature below:
)
$(DDOC_BLANKLINE )
$(GRAMMAR $(GNAME OpApplyDeclaration):
int opApply
$(LPAREN)
scope
int delegate
$(LPAREN)
$(I OpApplyParameters) $(RPAREN )
dg
$(RPAREN )
;
$(DDOC_BLANKLINE )
$(GNAME OpApplyParameters):
OpApplyParameter
OpApplyParameter, OpApplyParameters
$(DDOC_BLANKLINE )
$(GNAME OpApplyParameter):
$(GLINK ForeachTypeAttributes)$(OPT ) $(GLINK2 type, BasicType) $(GLINK2 declaration, Declarator)
)
$(DDOC_BLANKLINE )
$(P where each $(I OpApplyParameter) of dg
must match a $(GLINK ForeachType)
in a ForeachStatement,
otherwise the ForeachStatement will cause an error.)
$(DDOC_BLANKLINE )
$(P Any ForeachTypeAttribute cannot be enum
.)
$(DDOC_BLANKLINE )
$(PANEL To support a ref
iteration variable, the delegate must take a ref
parameter:
$(DDOC_BLANKLINE )
$(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD struct) S
{
$(D_KEYWORD int) opApply($(D_KEYWORD scope) $(D_KEYWORD int) $(D_KEYWORD delegate)($(D_KEYWORD ref) $(D_KEYWORD uint) n) dg);
}
$(D_KEYWORD void) f(S s)
{
$(D_KEYWORD foreach) ($(D_KEYWORD ref) $(D_KEYWORD uint) i; s)
i++;
}
)
)
Above, opApply
is still matched when i
is not ref
, so by using
a ref
delegate parameter both forms are supported.
)
$(DDOC_BLANKLINE )
$(P There can be multiple $(D opApply) and $(D opApplyReverse) functions -
one is selected
by matching each parameter of dg
to each $(I ForeachType)
declared in the $(I ForeachStatement).)
$(DDOC_BLANKLINE )
$(P The body of the apply
function iterates over the elements it aggregates, passing each one
in successive calls to the dg
delegate. The delegate return value
determines whether to interrupt iteration:)
$(DDOC_BLANKLINE )
$(UL $(LI If the result is nonzero, apply must cease
iterating and return that value.)
$(LI If the result is 0, then iteration should continue.
If there are no more elements to iterate,
apply must return 0.)
)
$(DDOC_BLANKLINE )
$(P For example, consider a class that is a container for two elements:)
$(DDOC_BLANKLINE )
$(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD class) Foo
{
$(D_KEYWORD uint)[2] array;
$(D_KEYWORD int) opApply($(D_KEYWORD scope) $(D_KEYWORD int) $(D_KEYWORD delegate)($(D_KEYWORD ref) $(D_KEYWORD uint)) dg)
{
$(D_KEYWORD foreach) (e; array)
{
$(D_KEYWORD int) result = dg(e);
$(D_KEYWORD if) (result)
$(D_KEYWORD return) result;
}
$(D_KEYWORD return) 0;
}
}
$(D_KEYWORD void) main()
{
$(D_KEYWORD import) std.stdio;
Foo a = $(D_KEYWORD new) Foo();
a.array = [73, 82];
$(D_KEYWORD foreach) ($(D_KEYWORD uint) u; a)
{
writeln(u);
}
}
)
)
$(DDOC_BLANKLINE )
$(P This would print:)
$(DDOC_BLANKLINE )
$(CONSOLE 73
82
)
$(PANEL The scope
storage class on the $(D dg) parameter means that the delegate does
not escape the scope of the $(D opApply) function (an example would be assigning $(D dg) to a
global variable). If it cannot be statically guaranteed that $(D dg) does not escape, a closure may
be allocated for it on the heap instead of the stack.
$(DDOC_BLANKLINE )
$(BEST_PRACTICE Annotate delegate parameters to opApply
functions with scope
when possible.)
)
$(DDOC_BLANKLINE )
$(P $(B Important:) If $(D opApply) catches any exceptions, ensure that those
exceptions did not originate from the delegate passed to $(D opApply). The user would expect
exceptions thrown from a foreach
body to both terminate the loop, and propagate outside
the foreach
body.
)
$(DDOC_BLANKLINE )
opApply
)front
property returns a type that
expands to a $(DDSUBLINK spec/template, homogeneous_sequences, value sequence)
whose length matches the number of variables. Each variable is assigned
to the corresponding value in the sequence.
)
$(DDOC_BLANKLINE )
$(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD struct) Tuple(Types...) $(D_COMMENT // takes a TypeSeq
){
Types items; $(D_COMMENT // ValueSeq
) $(D_KEYWORD alias) items $(D_KEYWORD this); $(D_COMMENT // decay to a value sequence
)}
$(D_COMMENT // Infinite range with a repeating element, which is a tuple
)$(D_KEYWORD struct) TupleRange
{
$(D_KEYWORD enum) front = Tuple!($(D_KEYWORD char), $(D_KEYWORD bool), $(D_KEYWORD int))('a', $(D_KEYWORD true), 2);
$(D_KEYWORD enum) $(D_KEYWORD bool) empty = $(D_KEYWORD false);
$(D_KEYWORD void) popFront() {}
}
$(D_KEYWORD void) main()
{
$(D_COMMENT // Tuple destructuring
) $(D_KEYWORD foreach) (a, b, c; TupleRange())
{
$(D_KEYWORD assert)(a == 'a');
$(D_KEYWORD assert)(b == $(D_KEYWORD true));
$(D_KEYWORD assert)(c == 2);
$(D_KEYWORD break);
}
$(D_COMMENT // Tuple variable
) $(D_KEYWORD foreach) (tup; TupleRange())
{
$(D_KEYWORD assert)(tup[0] == 'a');
$(D_KEYWORD assert)(tup == TupleRange.front);
$(D_KEYWORD break);
}
}
)
)
$(P See also: $(REF Tuple, std,typecons).)
$(DDOC_BLANKLINE )
int
, uint
, long
or ulong
type,
it cannot be ref
,
and it is set to the index of each sequence element.
)
$(P Example:)
$(DDOC_BLANKLINE )
$(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD import) std.meta : AliasSeq;
$(D_KEYWORD void) main()
{
$(D_KEYWORD alias) Seq = AliasSeq!($(D_KEYWORD int), $(D_STRING "literal"), main);
$(D_KEYWORD foreach) ($(D_KEYWORD int) i, sym; Seq)
{
$(D_KEYWORD pragma)(msg, i, $(D_STRING ": "), sym.stringof);
}
}
)
)
$(P Output:)
$(DDOC_BLANKLINE )
$(CONSOLE 0: int
1: "literal"
2: main()
)
$(DDOC_BLANKLINE )
$(P Example:)
$(DDOC_BLANKLINE )
$(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD void) fun()
{
$(D_KEYWORD import) std.meta : AliasSeq;
$(D_KEYWORD alias) values = AliasSeq!(7.4, $(D_STRING "hi"), [2,5]);
$(D_KEYWORD foreach) (sym; values)
{
$(D_KEYWORD pragma)(msg, sym, $(D_STRING " has type "), $(D_KEYWORD typeof)(sym));
}
}
)
)
$(DDOC_BLANKLINE )
$(P Output:)
$(DDOC_BLANKLINE )
$(CONSOLE 7.4 has type double
hi has type string
[2, 5] has type int[]
)
$(DDOC_BLANKLINE )
foreach
is iterating over the elements.
)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD int)[] a = [1, 2, 3];
$(D_KEYWORD auto) fun = { a ~= 4; };
$(D_KEYWORD foreach) ($(D_KEYWORD int) v; a)
{
$(D_COMMENT // resizing is unspecified!
) fun();
a ~= 4;
a.length += 10;
$(D_COMMENT // reallocating is unspecified!
) a.reserve(10);
$(D_COMMENT // reassigning is unspecified!
) a = $(D_KEYWORD null);
a = [5, 6];
}
a ~= 4; $(D_COMMENT // OK
)a = $(D_KEYWORD null); $(D_COMMENT // OK
))
$(D_CODE $(D_KEYWORD auto) aa = [1: 1, 2: 2];
$(D_KEYWORD foreach) (v; aa)
{
aa[3] = 3; $(D_COMMENT // unspecified resize
) aa.rehash; $(D_COMMENT // unspecified reallocation
) aa = [4: 4]; $(D_COMMENT // unspecified reassign
)}
aa[3] = 3; $(D_COMMENT // OK
)aa = $(D_KEYWORD null); $(D_COMMENT // OK
))
$(DDOC_BLANKLINE )
$(NOTE Resizing or reassigning a dynamic or associative array during
foreach
is still @safe
.
)
$(DDOC_BLANKLINE )
-
$(I LwrExpression).
If $(I UprExpression) is less than or equal to $(I LwrExpression),
the $(I ScopeStatement) is not executed.)
$(DDOC_BLANKLINE )
$(P If $(I Foreach) is $(D foreach), then the variable is set to
$(I LwrExpression), then incremented at the end of each iteration.
If $(I Foreach) is $(D foreach_reverse), then the variable is set to
$(I UprExpression), then decremented before each iteration.
$(I LwrExpression) and $(I UprExpression) are each evaluated
exactly once, regardless of how many times the $(I ScopeStatement)
is executed.
)
$(DDOC_BLANKLINE )
$(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD import) std.stdio;
$(D_KEYWORD int) foo()
{
write($(D_STRING "foo"));
$(D_KEYWORD return) 10;
}
$(D_KEYWORD void) main()
{
$(D_KEYWORD foreach) (i; 0 .. foo())
{
write(i);
}
}
)
)
$(DDOC_BLANKLINE )
prints:
$(DDOC_BLANKLINE )
$(CONSOLE foo0123456789
)
$(DDOC_BLANKLINE )
$(DDOC_BLANKLINE )
enum
, it is
(recursively) converted to its $(GLINK2 enum, EnumBaseType).
Then, if the type is an integral, $(I Expression) undergoes
$(DDSUBLINK spec/type, integer-promotions, Integer Promotions).
Then, the type of $(I Expression) must be either an integral or
a static or dynamic array of $(CODE char), $(CODE wchar), or $(CODE dchar).
)
$(DDOC_BLANKLINE )
$(P The resulting value is
compared against each of the case expressions. If there is
a match, the corresponding case statement is transferred to.
)
$(DDOC_BLANKLINE )
$(P The case expressions in $(I ArgumentList)
are a comma separated list of expressions.
Each expression must evaluate to a compile-time value or array,
or a runtime initialized const or immutable variable of integral type.
Each expression must be implicitly convertible to the type of the switch
Expression.)
$(DDOC_BLANKLINE )
$(P Compile-time case values must all be distinct. Const or
immutable runtime variables must all have different names.
If two case expressions share a
value, the first case statement with that value gets control.)
$(DDOC_BLANKLINE )
$(P The $(GLINK ScopeStatementList) introduces a new scope.
)
$(DDOC_BLANKLINE )
$(P A matching break
statement will exit the switch $(I BlockStatement).)
$(DDOC_BLANKLINE )
$(P A switch statement must have exactly one DefaultStatement.
If none of the case expressions match, control is transferred
to the default statement.
)
$(DDOC_BLANKLINE )
$(RATIONALE This makes it clear that all possible cases are intentionally handled.
See also: $(RELATIVE_LINK2 final-switch-statement, final switch
).)
$(DDOC_BLANKLINE )
$(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD foreach) (i; 2 .. 10)
{
$(D_KEYWORD bool) prime;
$(D_KEYWORD switch) (i)
{
$(D_KEYWORD case) 2, 3, 5, 7:
prime = $(D_KEYWORD true);
$(D_KEYWORD break);
$(D_KEYWORD default):
prime = $(D_KEYWORD false);
}
writeln(i, $(D_STRING ": "), prime);
}
)
)
$(P Case statements and default statements associated with the switch
can be nested within block statements; they do not have to be in
the outermost block. For example, this is allowed:
)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD switch) (i)
{
$(D_KEYWORD case) 1:
{
$(D_KEYWORD case) 2:
}
i++;
$(D_KEYWORD break);
$(D_KEYWORD default):
}
)
$(DDOC_BLANKLINE )
$(P $(B Implementation Note:) The compiler's code generator may
assume that the case
statements are sorted by frequency of use, with the most frequent
appearing first and the least frequent last. Although this is
irrelevant as far as program correctness is concerned, it is of
performance interest.
)
$(DDOC_BLANKLINE )
assert(0)
expression unless this is the last case.)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD switch) (i)
{
$(D_KEYWORD case) 1:
message ~= $(D_STRING "one");
$(D_COMMENT // ERROR: implicit fall-through
) $(D_KEYWORD case) 2:
$(D_COMMENT // valid: the body is empty
) $(D_KEYWORD default):
message ~= $(D_STRING "unknown");
}
)
$(DDOC_BLANKLINE )
$(P $(D goto case;) can be used for explicit fall-through:)
$(DDOC_BLANKLINE )
$(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE string message;
$(D_KEYWORD foreach) (i; 1..5)
{
$(D_KEYWORD switch) (i)
{
$(D_KEYWORD default): $(D_COMMENT // valid: ends with 'throw'
) $(D_KEYWORD throw) $(D_KEYWORD new) Exception($(D_STRING "unknown number"));
$(D_KEYWORD case) 3: $(D_COMMENT // valid: ends with 'break' $(LPAREN)break out of the 'switch' only$(RPAREN )
) message ~= $(D_STRING "three");
$(D_KEYWORD break);
$(D_KEYWORD case) 4: $(D_COMMENT // valid: ends with 'continue' $(LPAREN)continue the enclosing loop$(RPAREN )
) message ~= $(D_STRING "four");
$(D_KEYWORD continue); $(D_COMMENT // don't append a comma
)
$(D_KEYWORD case) 1: $(D_COMMENT // valid: ends with 'goto' $(LPAREN)explicit fall-through to next case.$(RPAREN )
) message ~= $(D_STRING ">");
$(D_KEYWORD goto) $(D_KEYWORD case);
$(D_KEYWORD case) 2: $(D_COMMENT // valid: this is the last case in the switch statement.
) message ~= $(D_STRING "one or two");
}
message ~= $(D_STRING ", ");
}
writeln(message);
)
)
$(P $(RELATIVE_LINK2 goto-statement, goto
) also supports jumping to
a specific case or the default case statement.)
$(DDOC_BLANKLINE )
char
, wchar
and dchar
strings are allowed.
)
$(DDOC_BLANKLINE )
$(DDOC_BLANKLINE )
continue
aborts the current iteration of its innermost enclosing
loop statement, and starts the next iteration.
If the enclosing loop is a for
statement,
its $(GLINK Increment) clause is executed.)
$(DDOC_BLANKLINE )
$(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE string[] words = [$(D_STRING "OK"), $(D_STRING "just"), $(D_STRING "longer"), $(D_STRING "words"), $(D_STRING "now")];
$(D_KEYWORD foreach) (w; words)
{
$(D_KEYWORD if) (w.length < 4)
$(D_KEYWORD continue); $(D_COMMENT // skip writeln
)
writeln(w);
}
)
)
$(P Output:)
$(DDOC_BLANKLINE )
$(CONSOLE just
longer
words
)
$(DDOC_BLANKLINE )
$(P If continue
is followed by $(I Identifier), the $(I Identifier)
must be the label of an enclosing loop statement,
and the next iteration of that loop is executed.
It is an error if
there is no such statement.)
$(DDOC_BLANKLINE )
$(D_CODE outer:
$(D_KEYWORD foreach) (item; list)
{
$(D_COMMENT // try 3 times
) $(D_KEYWORD foreach) (i; 0 .. 3)
{
$(D_KEYWORD if) (item.buy())
$(D_KEYWORD continue) outer; $(D_COMMENT // skip to next item
)
log($(D_STRING "attempt failed"));
}
}
)
$(DDOC_BLANKLINE )
$(P Any intervening $(RELATIVE_LINK2 try-statement, finally
) clauses are executed,
and any intervening synchronization objects are released.)
$(DDOC_BLANKLINE )
$(P $(D Note:) If a finally
clause executes a throw
out of the finally
clause, the continue target is never reached.)
$(DDOC_BLANKLINE )
break
exits the innermost enclosing loop or $(RELATIVE_LINK2 switch-statement, switch
)
statement, resuming execution at the statement following it.)
$(DDOC_BLANKLINE )
$(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD const) n = 55;
$(D_COMMENT // find the smallest factor of n
)$(D_KEYWORD foreach) (i; 2 .. n)
{
writeln($(D_STRING "Trying: "), i);
$(D_KEYWORD if) (n % i == 0)
{
writeln($(D_STRING "smallest factor is "), i);
$(D_KEYWORD break); $(D_COMMENT // stop looking
) }
}
writeln($(D_STRING "finished"));
)
)
$(P Output:)
$(DDOC_BLANKLINE )
$(CONSOLE Trying: 2
Trying: 3
Trying: 4
Trying: 5
smallest factor is 5
finished
)
$(DDOC_BLANKLINE )
$(P If break
is followed by $(I Identifier), the $(I Identifier)
must be the label of an enclosing loop or switch
statement, and that statement is exited. It is an error if
there is no such statement.)
$(DDOC_BLANKLINE )
$(D_CODE $(D_COMMENT // display messages cyclically until the shop is closed
)outer:
$(D_KEYWORD while) ($(D_KEYWORD true))
{
$(D_KEYWORD foreach) (msg; messages)
{
$(D_KEYWORD if) (shop.isClosed())
$(D_KEYWORD break) outer; $(D_COMMENT // end the while loop
)
display(msg);
}
}
display($(D_STRING "opens at 9am"));
)
$(DDOC_BLANKLINE )
$(P Any intervening $(RELATIVE_LINK2 try-statement, finally
) clauses are executed,
and any intervening synchronization objects are released.)
$(DDOC_BLANKLINE )
$(P $(D Note:) If a finally
clause executes a throw
out of the finally
clause, the break target is never reached.)
$(DDOC_BLANKLINE )
return
exits the current function and supplies its
$(DDSUBLINK spec/function, function-return-values, return value).)
$(DDOC_BLANKLINE )
$(P Expression is required if the function specifies a return type that is
not void. The Expression is implicitly converted to the function return
type.)
$(DDOC_BLANKLINE )
$(P An Expression of type void is allowed if the function specifies
a void return type. The Expression will be evaluated,
but nothing will be returned. This is useful in generic programming.
)
$(P Before the function actually returns,
any objects with scope
storage duration are destroyed,
any enclosing finally
clauses are executed,
any scope(exit)
statements are executed,
any scope(success)
statements are executed,
and any enclosing synchronization
objects are released.)
$(DDOC_BLANKLINE )
$(P The function will not return if any enclosing finally
clause
does a return, goto or throw that exits the finally
clause.)
$(DDOC_BLANKLINE )
$(P If there is an $(DDSUBLINK spec/function, postconditions, out
postcondition),
that postcondition is executed
after the Expression is evaluated and before the function
actually returns.)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD int) foo($(D_KEYWORD int) x)
{
$(D_KEYWORD return) x + 3;
}
)
$(DDOC_BLANKLINE )
goto
transfers to the statement labeled with $(I Identifier).)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD if) (foo)
$(D_KEYWORD goto) L1;
x = 3;
L1:
x++;
)
$(DDOC_BLANKLINE )
$(P The second form, $(CODE goto default;), transfers to the innermost $(GLINK DefaultStatement) of an enclosing $(GLINK SwitchStatement).)
$(DDOC_BLANKLINE )
$(P The third form, $(CODE goto case;), transfers to the
next $(GLINK CaseStatement) of the innermost enclosing
$(GLINK SwitchStatement).)
$(DDOC_BLANKLINE )
$(P The fourth form, $(CODE goto case) Expression$(D ;), transfers to the
$(GLINK CaseStatement) of the innermost enclosing
$(GLINK SwitchStatement)
with a matching Expression.)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD switch) (x)
{
$(D_KEYWORD case) 3:
$(D_KEYWORD goto) $(D_KEYWORD case);
$(D_KEYWORD case) 4:
$(D_KEYWORD goto) $(D_KEYWORD default);
$(D_KEYWORD case) 5:
$(D_KEYWORD goto) $(D_KEYWORD case) 4;
$(D_KEYWORD default):
x = 4;
$(D_KEYWORD break);
}
)
$(DDOC_BLANKLINE )
$(P Any intervening finally clauses are executed, along with releasing any
intervening synchronization mutexes.)
$(DDOC_BLANKLINE )
$(P It is illegal for a $(I GotoStatement) to be used to skip
initializations.)
$(DDOC_BLANKLINE )
with
statement is a way to simplify repeated references to the same
object.)
$(DDOC_BLANKLINE )
$(GRAMMAR $(GNAME WithStatement):
$(D with) $(D $(LPAREN)) $(GLINK2 expression, Expression) $(D $(RPAREN )) $(GLINK ScopeStatement)
$(D with) $(D $(LPAREN)) $(GLINK2 template, Symbol) $(D $(RPAREN )) $(GLINK ScopeStatement)
$(D with) $(D $(LPAREN)) $(GLINK2 template, TemplateInstance) $(D $(RPAREN )) $(GLINK ScopeStatement)
)
$(DDOC_BLANKLINE )
where Expression evaluates to one of:
$(DDOC_BLANKLINE )
$(UL $(LI a class reference)
$(LI a struct instance)
$(LI an enum instance)
$(LI a pointer to one of the above)
)
$(DDOC_BLANKLINE )
Within the with body the referenced object is searched first for
identifier symbols.
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD enum) E { A, B }
$(D_KEYWORD void) test(E e)
{
$(D_KEYWORD with) (e) $(D_COMMENT // affects the switch statement
) $(D_KEYWORD switch) (e)
{
$(D_KEYWORD case) A: $(D_COMMENT // no need for E.A
) $(D_KEYWORD case) B:
$(D_KEYWORD default):
$(D_KEYWORD break);
}
}
)
$(DDOC_BLANKLINE )
$(P Below, if ident
is a member of the type of expression
, the $(I WithStatement):)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD with) (expression)
{
...
ident;
}
)
$(DDOC_BLANKLINE )
is semantically equivalent to:
$(DDOC_BLANKLINE )
$(D_CODE ($(D_KEYWORD auto) $(D_KEYWORD ref) tmp)
{
...
tmp.ident;
}(expression);
)
$(DDOC_BLANKLINE )
$(P Note that Expression only gets evaluated once and is not copied.
The with statement does not change what $(D this) or
$(D super) refer to.
)
$(DDOC_BLANKLINE )
$(P For $(I Symbol) which is a scope or $(I TemplateInstance),
the corresponding scope is searched when looking up symbols.
For example:
)
$(DDOC_BLANKLINE )
$(D_CODE $(D_KEYWORD struct) Foo
{
$(D_KEYWORD alias) Y = $(D_KEYWORD int);
}
...
Y y; $(D_COMMENT // error, Y undefined
)$(D_KEYWORD with) (Foo)
{
Y y; $(D_COMMENT // same as Foo.Y y;
)}
)
$(DDOC_BLANKLINE )
$(P Use of with
object symbols that shadow local symbols with
the same identifier are not allowed.
This is to reduce the risk of inadvertent breakage of with
statements when new members are added to the object declaration.
)
$(D_CODE $(D_KEYWORD struct) S
{
$(D_KEYWORD float) x;
}
$(D_KEYWORD void) main()
{
$(D_KEYWORD int) x;
S s;
$(D_KEYWORD with) (s)
{
x++; $(D_COMMENT // error, shadows the int x declaration
) }
}
)
$(DDOC_BLANKLINE )
$(P In nested $(I WithStatement)s, the inner-most scope takes precedence. If
a symbol cannot be resolved at the inner-most scope, resolution is forwarded
incrementally up the scope hierarchy.)
$(DDOC_BLANKLINE )
$(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD import) std.stdio;
$(D_KEYWORD struct) Foo
{
$(D_KEYWORD void) f() { writeln($(D_STRING "Foo.f")); }
}
$(D_KEYWORD struct) Bar
{
$(D_KEYWORD void) f() { writeln($(D_STRING "Bar.f")); }
}
$(D_KEYWORD struct) Baz
{
$(D_COMMENT // f$(LPAREN)$(RPAREN ) is not implemented
)}
$(D_KEYWORD void) f()
{
writeln($(D_STRING "f"));
}
$(D_KEYWORD void) main()
{
Foo foo;
Bar bar;
Baz baz;
f(); $(D_COMMENT // prints "f"
)
$(D_KEYWORD with)(foo)
{
f(); $(D_COMMENT // prints "Foo.f"
)
$(D_KEYWORD with)(bar)
{
f(); $(D_COMMENT // prints "Bar.f"
)
$(D_KEYWORD with)(baz)
{
f(); $(D_COMMENT // prints "Bar.f". `Baz` does not implement `f$(LPAREN)$(RPAREN )` so
) $(D_COMMENT // resolution is forwarded to `with$(LPAREN)bar$(RPAREN )`'s scope
) }
}
$(D_KEYWORD with)(baz)
{
f(); $(D_COMMENT // prints "Foo.f". `Baz` does not implement `f$(LPAREN)$(RPAREN )` so
) $(D_COMMENT // resolution is forwarded to `with$(LPAREN)foo$(RPAREN )`'s scope
) }
}
$(D_KEYWORD with)(baz)
{
f(); $(D_COMMENT // prints "f". `Baz` does not implement `f$(LPAREN)$(RPAREN )` so
) $(D_COMMENT // resolution is forwarded to `main`'s scope. `f$(LPAREN)$(RPAREN )` is
) $(D_COMMENT // not implemented in `main`'s scope, so resolution is
) $(D_COMMENT // subsequently forward to module scope.
) }
}
)
)
$(DDOC_BLANKLINE )
scope(success)
executes NonEmptyOrScopeBlockStatement when the scope exits normally.)
$(DDOC_BLANKLINE )
$(P If there are multiple $(I ScopeGuardStatement)s in a scope, they
will be executed in the reverse lexical order in which they appear.
If any scope instances are to be destroyed upon the close of the
scope, their destructions will be interleaved with the $(I ScopeGuardStatement)s
in the reverse lexical order in which they appear.)
$(DDOC_BLANKLINE )
$(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE write($(D_STRING "1"));
{
write($(D_STRING "2"));
$(D_KEYWORD scope)(exit) write($(D_STRING "3"));
$(D_KEYWORD scope)(exit) write($(D_STRING "4"));
write($(D_STRING "5"));
}
writeln();
)
)
$(DDOC_BLANKLINE )
writes:
$(DDOC_BLANKLINE )
$(CONSOLE 12543
)
$(DDOC_BLANKLINE )
$(DDOC_BLANKLINE )
$(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE {
$(D_KEYWORD scope)(exit) write($(D_STRING "1"));
$(D_KEYWORD scope)(success) write($(D_STRING "2"));
$(D_KEYWORD scope)(exit) write($(D_STRING "3"));
$(D_KEYWORD scope)(success) write($(D_STRING "4"));
}
writeln();
)
)
$(DDOC_BLANKLINE )
writes:
$(DDOC_BLANKLINE )
$(CONSOLE 4321
)
$(DDOC_BLANKLINE )
$(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD struct) Foo
{
$(D_KEYWORD this)(string s) { write(s); }
~$(D_KEYWORD this)() { write($(D_STRING "1")); }
}
$(D_KEYWORD try)
{
$(D_KEYWORD scope)(exit) write($(D_STRING "2"));
$(D_KEYWORD scope)(success) write($(D_STRING "3"));
Foo f = Foo($(D_STRING "0"));
$(D_KEYWORD scope)(failure) write($(D_STRING "4"));
$(D_KEYWORD throw) $(D_KEYWORD new) Exception($(D_STRING "msg"));
$(D_KEYWORD scope)(exit) write($(D_STRING "5"));
$(D_KEYWORD scope)(success) write($(D_STRING "6"));
$(D_KEYWORD scope)(failure) write($(D_STRING "7"));
}
$(D_KEYWORD catch) (Exception e)
{
}
writeln();
)
)
$(DDOC_BLANKLINE )
writes:
$(DDOC_BLANKLINE )
$(CONSOLE 0412
)
$(DDOC_BLANKLINE )
A $(D scope(exit)) or $(D scope(success)) statement
may not exit with a throw, goto, break, continue, or
return; nor may it be entered with a goto. A $(D scope(failure))
statement may not exit with a return.
$(DDOC_BLANKLINE )
$(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD import) std.stdio;
$(D_KEYWORD int) foo()
{
$(D_KEYWORD scope)(exit) writeln($(D_STRING "Inside foo$(LPAREN)$(RPAREN )"));
$(D_KEYWORD return) bar();
}
$(D_KEYWORD int) bar()
{
writeln($(D_STRING "Inside bar$(LPAREN)$(RPAREN )"));
$(D_KEYWORD return) 0;
}
$(D_KEYWORD int) main()
{
foo();
$(D_KEYWORD return) 0;
}
)
)
$(DDOC_BLANKLINE )
writes:
$(DDOC_BLANKLINE )
$(CONSOLE Inside bar()
Inside foo()
)
$(DDOC_BLANKLINE )