$(DDOC $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE ) $(SPEC_S Expressions, $(DDOC_BLANKLINE ) $(HEADERNAV_TOC $(HEADERNAV_ITEM expression, Expressions) $(HEADERNAV_SUBITEMS definitions-and-terms, Definitions and Terms, $(HEADERNAV_ITEM .define-full-expression, Full Expression) $(HEADERNAV_ITEM .define-lvalue, Lvalue) $(HEADERNAV_ITEM .define-rvalue, Rvalue) $(HEADERNAV_ITEM .define-smallest-short-circuit, Smallest Short-Circuit Expression) ) $(HEADERNAV_ITEM order-of-evaluation, Order Of Evaluation) $(HEADERNAV_ITEM temporary-lifetime, Lifetime of Temporaries) $(HEADERNAV_ITEM comma_expression, Comma Expression) $(HEADERNAV_SUBITEMS assign_expressions, Assign Expressions, $(HEADERNAV_ITEM simple_assignment_expressions, Simple Assignment Expression) $(HEADERNAV_ITEM assignment_operator_expressions, Assignment Operator Expressions) ) $(HEADERNAV_ITEM conditional_expressions, Conditional Expressions) $(HEADERNAV_SUBITEMS logical_expressions, Logical Expressions, $(HEADERNAV_ITEM oror_expressions, OrOr Expressions) $(HEADERNAV_ITEM andand_expressions, AndAnd Expressions) ) $(HEADERNAV_SUBITEMS bitwise_expressions, Bitwise Expressions, $(HEADERNAV_ITEM or_expressions, Or Expressions) $(HEADERNAV_ITEM xor_expressions, Xor Expressions) $(HEADERNAV_ITEM and_expressions, And Expressions) ) $(HEADERNAV_SUBITEMS compare_expressions, Compare Expressions, $(HEADERNAV_ITEM equality_expressions, Equality Expressions) $(HEADERNAV_ITEM identity_expressions, Identity Expressions) $(HEADERNAV_ITEM relation_expressions, Relational Expressions) $(HEADERNAV_ITEM array_comparisons, Array Comparisons) $(HEADERNAV_ITEM integer_comparisons, Integer Comparisons) $(HEADERNAV_ITEM floating-point-comparisons, Floating Point Comparisons) $(HEADERNAV_ITEM class-comparisons, Class Comparisons) ) $(HEADERNAV_ITEM in_expressions, In Expressions) $(HEADERNAV_ITEM shift_expressions, Shift Expressions) $(HEADERNAV_SUBITEMS additive_expressions, Additive Expressions, $(HEADERNAV_ITEM add_expressions, Add Expressions) $(HEADERNAV_ITEM cat_expressions, Cat Expressions) ) $(HEADERNAV_SUBITEMS mul_expressions, Mul Expressions, $(HEADERNAV_ITEM division, Division) $(HEADERNAV_ITEM mul_floating, Floating Point) ) $(HEADERNAV_SUBITEMS unary-expression, Unary Expressions, $(HEADERNAV_ITEM complement_expressions, Complement Expressions) $(HEADERNAV_ITEM delete_expressions, Delete Expressions) $(HEADERNAV_ITEM cast_expressions, Cast Expressions) ) $(HEADERNAV_ITEM throw_expression, Throw Expression) $(HEADERNAV_ITEM pow_expressions, Pow Expressions) $(HEADERNAV_SUBITEMS postfix_expressions, Postfix Expressions, $(HEADERNAV_ITEM argument-list, Postfix Argument Lists) $(HEADERNAV_ITEM index_expressions, Index Operations) $(HEADERNAV_ITEM slice_expressions, Slice Operations) ) $(HEADERNAV_SUBITEMS primary_expressions, Primary Expressions, $(HEADERNAV_ITEM identifier, .Identifier) $(HEADERNAV_ITEM this, this) $(HEADERNAV_ITEM super, super) $(HEADERNAV_ITEM null, null) $(HEADERNAV_ITEM string_literals, String Literals) $(HEADERNAV_ITEM array_literals, Array Literals) $(HEADERNAV_ITEM associative_array_literals, Associative Array Literals) $(HEADERNAV_ITEM function_literals, Function Literals) $(HEADERNAV_ITEM uniform_construction_syntax, Uniform construction syntax for built-in scalar types) $(HEADERNAV_ITEM assert_expressions, Assert Expressions) $(HEADERNAV_ITEM mixin_expressions, Mixin Expressions) $(HEADERNAV_ITEM import_expressions, Import Expressions) $(HEADERNAV_ITEM new_expressions, New Expressions) $(HEADERNAV_ITEM typeid_expressions, Typeid Expressions) $(HEADERNAV_ITEM is_expression, Is Expressions) $(HEADERNAV_ITEM specialkeywords, Special Keywords) ) $(HEADERNAV_ITEM associativity, Associativity and Commutativity) ) $(DDOC_BLANKLINE )

$(LEGACY_LNAME2 Expression, expression, Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME Expression): $(GLINK CommaExpression) ) $(DDOC_BLANKLINE ) $(P An expression is a sequence of operators and operands that specifies an evaluation. The syntax, order of evaluation, and semantics of expressions are as follows.) $(DDOC_BLANKLINE ) $(P Expressions are used to compute values with a resulting type. These values can then be assigned, tested, or ignored. Expressions can also have side effects. ) $(DDOC_BLANKLINE )

$(LNAME2 definitions-and-terms, Definitions and Terms)

$(DDOC_BLANKLINE )

$(LNAME2 .define-full-expression, Full Expression)

$(DDOC_BLANKLINE ) $(P For any expression $(I expr), the full expression of $(I expr) is defined as follows. If $(I expr) parses as a subexpression of another expression $(I expr$(SUBSCRIPT 1)), then the full expression of $(I expr) is the full expression of $(I expr$(SUBSCRIPT 1)). Otherwise, $(I expr) is its own full expression.) $(DDOC_BLANKLINE ) $(P Each expression has a unique full expression. Example:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD return) f() + g() * 2; ) $(DDOC_BLANKLINE ) $(P The full expression of g() * 2 above is f() + g() * 2, but not the full expression of f() + g() because the latter is not parsed as a subexpression.) $(DDOC_BLANKLINE ) $(P Note: Although the definition is straightforward, a few subtleties exist related to function literals:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD return) (() => x + f())() * g(); ) $(DDOC_BLANKLINE ) $(P The full expression of f() above is x + f(), not the expression passed to return. This is because the parent of x + f() has function literal type, not expression type.) $(DDOC_BLANKLINE )

$(LNAME2 .define-lvalue, Lvalue)

$(DDOC_BLANKLINE ) $(P The following expressions, and no others, are called lvalue expressions or lvalues:) $(OL $(LI $(RELATIVE_LINK2 this, this) inside struct and union member functions;) $(LI a variable, function name, or invocation of a function that returns by reference;) $(LI the result of the . $(GLINK PostfixExpression) or $(DDSUBLINK spec/module, module_scope_operators, Module Scope Operator) when the rightmost side of the dot is a variable, field (direct or static), function name, or invocation of a function that returns by reference;) $(LI the result of the following expressions: $(UL $(LI built-in unary operators + (when applied to an lvalue), *, ++ (prefix only), -- (prefix only);) $(LI built-in indexing operator [] (but not the slicing operator);) $(LI built-in assignment binary operators, i.e. =, +=, *=, /=, %=, &=, |=, ^=, ~=, <<=, >>=, >>>=, and ^^=;) $(LI the $(GLINK ConditionalExpression) operator $(I e) ? $(I e$(SUBSCRIPT 1)) : $(I e$(SUBSCRIPT 2)) under the following circumstances:) $(OL $(LI $(I e$(SUBSCRIPT 1)) and $(I e$(SUBSCRIPT 2)) are lvalues of the same type; OR) $(LI One of $(I e$(SUBSCRIPT 1)) and $(I e$(SUBSCRIPT 2)) is an lvalue of type T and the other has and alias this converting it to ref T;)) $(LI $(DDLINK spec/operatoroverloading, Operator Overloading, user-defined operators) if and only if the function called as a result of lowering returns by reference;) $(LI $(RELATIVE_LINK2 mixin_expressions, mixin expressions) if and only if the compilation of the expression resulting from compiling the argument(s) to mixin is an lvalue;) $(LI cast(U) expressions applied to lvalues of type T when T* is implicitly convertible to U*;) $(LI cast() and cast$(LPAREN)$(I qualifier list)$(RPAREN ) when applied to an lvalue.) ))) $(DDOC_BLANKLINE )

$(LNAME2 .define-rvalue, Rvalue)

$(DDOC_BLANKLINE ) $(P Expressions that are not lvalues are rvalues. Rvalues include all literals, special value keywords such as __FILE__ and __LINE__, enum values, and the result of expressions not defined as lvalues above.) $(DDOC_BLANKLINE ) $(P The built-in address-of operator (unary &) may only be applied to lvalues.) $(DDOC_BLANKLINE )

$(LNAME2 .define-smallest-short-circuit, Smallest Short-Circuit Expression)

$(DDOC_BLANKLINE ) $(P Given an expression $(I expr) that is a subexpression of a full expression $(I fullexpr), the smallest short-circuit expression, if any, is the shortest subexpression $(I scexpr) of $(I fullexpr) that is an $(GLINK AndAndExpression) (&&) or an $(GLINK OrOrExpression) (||), such that $(I expr) is a subexpression of $(I scexpr). Example:) $(D_CODE ((f() * 2 && g()) + 1) || h() ) The smallest short-circuit expression of the subexpression f() * 2 above is f() * 2 && g(). Example: $(D_CODE (f() && g()) + h() ) The subexpression h() above has no smallest short-circuit expression. $(DDOC_BLANKLINE )

$(LNAME2 order-of-evaluation, Order Of Evaluation)

$(DDOC_BLANKLINE ) $(P Built-in prefix unary expressions ++ and -- are evaluated as if lowered (rewritten) to $(RELATIVE_LINK2 assignment_operator_expressions, assignments) as follows:) $(DDOC_BLANKLINE ) $(TABLE Expression, Equivalent $(TROW ++expr, ((expr) += 1)) $(TROW --expr, ((expr) -= 1)) ) $(P Therefore, the result of prefix ++ and -- is the lvalue after the side effect has been effected.) $(DDOC_BLANKLINE ) $(P Built-in postfix unary expressions ++ and -- are evaluated as if lowered (rewritten) to $(DDSUBLINK spec/expression, function_literals, lambda) invocations as follows:) $(DDOC_BLANKLINE ) $(TABLE Expression, Equivalent $(TROW expr++, (ref x){auto t = x; ++x; return t;}(expr)) $(TROW expr--, (ref x){auto t = x; --x; return t;}(expr)) ) $(P Therefore, the result of postfix ++ and -- is an rvalue just before the side effect has been effected.) $(DDOC_BLANKLINE ) $(P Binary expressions except for $(GLINK AssignExpression), $(GLINK OrOrExpression), and $(GLINK AndAndExpression) are evaluated in lexical order (left-to-right). Example:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD int) i = 2; i = ++i * i++ + i; $(D_KEYWORD assert)(i == 3 * 3 + 4); ) ) $(DDOC_BLANKLINE ) $(P $(GLINK OrOrExpression) and $(GLINK AndAndExpression) evaluate their left-hand side argument first. Then, $(GLINK OrOrExpression) evaluates its right-hand side if and only if its left-hand side does not evaluate to nonzero. $(GLINK AndAndExpression) evaluates its right-hand side if and only if its left-hand side evaluates to nonzero.) $(DDOC_BLANKLINE ) $(P $(GLINK ConditionalExpression) evaluates its left-hand side argument first. Then, if the result is nonzero, the second operand is evaluated. Otherwise, the third operand is evaluated.) $(DDOC_BLANKLINE ) $(P Calls to functions with extern(D) $(DDSUBLINK spec/attribute, linkage, linkage) (which is the default linkage) are evaluated in the following order: first, if necessary, the address of the function to call is evaluated (e.g. in the case of a computed function pointer or delegate). Then, arguments are evaluated left to right. Finally, transfer is passed to the function. Example:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD void) $(D_KEYWORD function)($(D_KEYWORD int) a, $(D_KEYWORD int) b, $(D_KEYWORD int) c) fun() { writeln($(D_STRING "fun$(LPAREN)$(RPAREN ) called")); $(D_KEYWORD static) $(D_KEYWORD void) r($(D_KEYWORD int) a, $(D_KEYWORD int) b, $(D_KEYWORD int) c) { writeln($(D_STRING "callee called")); } $(D_KEYWORD return) &r; } $(D_KEYWORD int) f1() { writeln($(D_STRING "f1$(LPAREN)$(RPAREN ) called")); $(D_KEYWORD return) 1; } $(D_KEYWORD int) f2() { writeln($(D_STRING "f2$(LPAREN)$(RPAREN ) called")); $(D_KEYWORD return) 2; } $(D_KEYWORD int) f3($(D_KEYWORD int) x) { writeln($(D_STRING "f3$(LPAREN)$(RPAREN ) called")); $(D_KEYWORD return) x + 3; } $(D_KEYWORD int) f4() { writeln($(D_STRING "f4$(LPAREN)$(RPAREN ) called")); $(D_KEYWORD return) 4; } $(D_COMMENT // evaluates fun$(LPAREN)$(RPAREN ) then f1$(LPAREN)$(RPAREN ) then f2$(LPAREN)$(RPAREN ) then f3$(LPAREN)$(RPAREN ) then f4$(LPAREN)$(RPAREN ) )$(D_COMMENT // after which control is transferred to the callee )fun()(f1(), f3(f2()), f4()); ) ) $(DDOC_BLANKLINE ) $(IMPLEMENTATION_DEFINED $(OL $(LI The order of evaluation of the operands of $(GLINK AssignExpression).) $(LI The order of evaluation of function arguments for functions with linkage other than extern (D).) )) $(DDOC_BLANKLINE ) $(BEST_PRACTICE Even though the order of evaluation is well-defined, writing code that depends on it is rarely recommended.) $(DDOC_BLANKLINE )

$(LNAME2 temporary-lifetime, Lifetime of Temporaries)

$(DDOC_BLANKLINE ) $(P Expressions and statements may create and/or consume rvalues. Such values are called $(I temporaries) and do not have a name or a visible scope. Their lifetime is managed automatically as defined in this section.) $(DDOC_BLANKLINE ) $(P For each evaluation that yields a temporary value, the lifetime of that temporary begins at the evaluation point, similarly to creation of a usual named value initialized with an expression.) $(DDOC_BLANKLINE ) $(P Termination of lifetime of temporaries does not obey the customary scoping rules and is defined as follows:) $(DDOC_BLANKLINE ) $(UL $(LI If: $(OL $(LI the full expression has a smallest short-circuit expression $(I expr); and) $(LI the temporary is created on the right-hand side of the && or || operator; and) $(LI the right-hand side is evaluated,)) then temporary destructors are evaluated right after the right-hand side expression has been evaluated and converted to bool. Evaluation of destructors proceeds in reverse order of construction.) $(DDOC_BLANKLINE ) $(LI For all other cases, the temporaries generated for the purpose of invoking functions are deferred to the end of the full expression. The order of destruction is inverse to the order of construction.)) $(DDOC_BLANKLINE ) $(P If a subexpression of an expression throws an exception, all temporaries created up to the evaluation of that subexpression will be destroyed per the rules above. No destructor calls will be issued for temporaries not yet constructed.) $(DDOC_BLANKLINE ) $(P Note: An intuition behind these rules is that destructors of temporaries are deferred to the end of full expression and in reverse order of construction, with the exception that the right-hand side of && and || are considered their own full expressions even when part of larger expressions.) $(DDOC_BLANKLINE ) $(P Note: The $(GLINK ConditionalExpression) $(I e$(SUBSCRIPT 1) ? e$(SUBSCRIPT 2) : e$(SUBSCRIPT 3)) is not a special case although it evaluates expressions conditionally: $(I e$(SUBSCRIPT 1)) and one of $(I e$(SUBSCRIPT 2)) and $(I e$(SUBSCRIPT 3)) may create temporaries. Their destructors are inserted to the end of the full expression in the reverse order of creation.) $(DDOC_BLANKLINE ) $(P Example:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD import) std.stdio; $(D_KEYWORD struct) S { $(D_KEYWORD int) x; $(D_KEYWORD this)($(D_KEYWORD int) n) { x = n; writefln($(D_STRING "S$(LPAREN)%s$(RPAREN )"), x); } ~$(D_KEYWORD this)() { writefln($(D_STRING "~S$(LPAREN)%s$(RPAREN )"), x); } } $(D_KEYWORD void) main() { $(D_KEYWORD bool) b = (S(1) == S(2) || S(3) != S(4)) && S(5) == S(6); } ) ) $(DDOC_BLANKLINE ) The output of the code above is: $(DDOC_BLANKLINE ) $(CONSOLE S(1) S(2) S(3) S(4) ~S(4) ~S(3) S(5) S(6) ~S(6) ~S(5) ~S(2) ~S(1) ) $(DDOC_BLANKLINE ) First, S(1) and S(2) are evaluated in lexical order. Per the rules, they will be destroyed at the end of the full expression and in reverse order. The comparison $(D S(1) == S(2)) yields false, so the right-hand side of the || is evaluated causing S(3) and S(4) to be evaluated, also in lexical order. However, their destruction is not deferred to the end of the full expression. Instead, S(4) and then S(3) are destroyed at the end of the || expression. Following their destruction, S(5) and S(6) are constructed in lexical order. Again they are not destroyed at the end of the full expression, but right at the end of the && expression. Consequently, the destruction of S(6) and S(5) is carried before that of S(2) and S(1). $(DDOC_BLANKLINE )

$(LNAME2 comma_expression, Comma Expression)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME CommaExpression): $(GLINK AssignExpression) $(GSELF CommaExpression) $(D ,) $(GLINK AssignExpression) ) $(DDOC_BLANKLINE ) $(P The left operand of the $(D ,) is evaluated, then the right operand is evaluated. The type of the expression is the type of the right operand, and the result is the result of the right operand. Using the result of comma expressions isn't allowed. ) $(DDOC_BLANKLINE )

$(LNAME2 assign_expressions, Assign Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME AssignExpression): $(GLINK ConditionalExpression) $(GLINK ConditionalExpression) $(D =) $(GSELF AssignExpression) $(GLINK ConditionalExpression) $(D +=) $(GSELF AssignExpression) $(GLINK ConditionalExpression) $(D -=) $(GSELF AssignExpression) $(GLINK ConditionalExpression) $(D *=) $(GSELF AssignExpression) $(GLINK ConditionalExpression) $(D /=) $(GSELF AssignExpression) $(GLINK ConditionalExpression) $(D %=) $(GSELF AssignExpression) $(GLINK ConditionalExpression) $(D &=) $(GSELF AssignExpression) $(GLINK ConditionalExpression) $(D |=) $(GSELF AssignExpression) $(GLINK ConditionalExpression) $(D ^=) $(GSELF AssignExpression) $(GLINK ConditionalExpression) $(D ~=) $(GSELF AssignExpression) $(GLINK ConditionalExpression) $(D <<=) $(GSELF AssignExpression) $(GLINK ConditionalExpression) $(D >>=) $(GSELF AssignExpression) $(GLINK ConditionalExpression) $(D >>>=) $(GSELF AssignExpression) $(GLINK ConditionalExpression) $(D ^^=) $(GSELF AssignExpression) ) $(DDOC_BLANKLINE ) $(P For all assign expressions, the left operand must be a modifiable lvalue. The type of the assign expression is the type of the left operand, and the result is the value of the left operand after assignment occurs. The resulting expression is a modifiable lvalue. ) $(DDOC_BLANKLINE ) $(UNDEFINED_BEHAVIOR If either operand is a reference type and one of the following: $(OL $(LI the operands have partially overlapping storage) $(LI the operands' storage overlaps exactly but the types are different) )) $(DDOC_BLANKLINE ) $(IMPLEMENTATION_DEFINED If neither operand is a reference type and one of the following: $(OL $(LI the operands have partially overlapping storage) $(LI the operands' storage overlaps exactly but the types are different) )) $(DDOC_BLANKLINE )

$(LNAME2 simple_assignment_expressions, Simple Assignment Expression)

$(DDOC_BLANKLINE ) $(P If the operator is $(D =) then it is simple assignment. ) $(DDOC_BLANKLINE ) $(UL $(LI If the left operand is a struct that $(DDSUBLINK spec/operatoroverloading, assignment, defines opAssign), the behaviour is defined by the overloaded function. ) $(DDOC_BLANKLINE ) $(LI If the left and right operands are of the same struct type, and the struct type has a $(GLINK2 struct, Postblit), then the copy operation is as described in $(DDSUBLINK spec/struct, struct-postblit, Struct Postblit). ) $(DDOC_BLANKLINE ) $(LI If the lvalue is the .length property of a dynamic array, the behavior is as described in $(DDSUBLINK spec/arrays, resize, Setting Dynamic Array Length). ) $(DDOC_BLANKLINE ) $(LI If the lvalue is a static array or a slice, the behavior is as described in $(DDSUBLINK spec/arrays, array-copying, Array Copying) and $(DDSUBLINK spec/arrays, array-setting, Array Setting). ) $(DDOC_BLANKLINE ) $(LI If the lvalue is a user-defined property, the behavior is as described in $(DDSUBLINK spec/function, property-functions, Property Functions). ) ) $(DDOC_BLANKLINE ) $(P Otherwise, the right operand is implicitly converted to the type of the left operand, and assigned to it.) $(DDOC_BLANKLINE )

$(LNAME2 assignment_operator_expressions, Assignment Operator Expressions)

$(DDOC_BLANKLINE ) $(P For arguments of built-in types, assignment operator expressions such as) $(DDOC_BLANKLINE ) $(D_CODE a op= b ) $(DDOC_BLANKLINE ) are semantically equivalent to: $(DDOC_BLANKLINE ) $(D_CODE a = $(D_KEYWORD cast)($(D_KEYWORD typeof)(a))(a op b) ) $(DDOC_BLANKLINE ) except that: $(DDOC_BLANKLINE ) $(UL $(LI operand $(D a) is only evaluated once,) $(LI overloading $(I op) uses a different function than overloading $(I op)= does, and) $(LI the left operand of $(D >>>=) does not undergo $(DDSUBLINK spec/type, integer-promotions, Integer Promotions) before shifting.) ) $(DDOC_BLANKLINE ) $(P For user-defined types, assignment operator expressions are $(DDSUBLINK spec/operatoroverloading, op-assign, overloaded separately) from the binary operators. Still the left operand must be an lvalue. ) $(DDOC_BLANKLINE )

$(LNAME2 conditional_expressions, Conditional Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME ConditionalExpression): $(GLINK OrOrExpression) $(GLINK OrOrExpression) $(D ?) $(GLINK Expression) $(D :) $(GSELF ConditionalExpression) ) $(DDOC_BLANKLINE ) $(P The first expression is converted to $(D bool), and is evaluated. ) $(DDOC_BLANKLINE ) $(P If it is $(D true), then the second expression is evaluated, and its result is the result of the conditional expression. ) $(DDOC_BLANKLINE ) $(P If it is $(D false), then the third expression is evaluated, and its result is the result of the conditional expression. ) $(DDOC_BLANKLINE ) $(P If either the second or third expressions are of type $(D void), then the resulting type is $(D void). Otherwise, the second and third expressions are implicitly converted to a common type which becomes the result type of the conditional expression. ) $(DDOC_BLANKLINE ) $(PANEL $(NOTE When a conditional expression is the left operand of an $(RELATIVE_LINK2 assign_expressions, assign expression), parentheses are required for disambiguation: ) $(D_CODE $(D_KEYWORD bool) test; $(D_KEYWORD int) a, b, c; ... test ? a = b : c = 2; $(D_COMMENT // error )(test ? a = b : c) = 2; $(D_COMMENT // OK )) $(DDOC_BLANKLINE ) $(P This makes the intent clearer, because the first statement can easily be misread as the following code: ) $(D_CODE test ? a = b : (c = 2); ) ) $(DDOC_BLANKLINE )

$(LNAME2 logical_expressions, Logical Expressions)

$(DDOC_BLANKLINE ) $(DDOC_SEE_ALSO $(GLINK UnaryExpression) for !expr.) $(DDOC_BLANKLINE )

$(LNAME2 oror_expressions, OrOr Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME OrOrExpression): $(GLINK AndAndExpression) $(GSELF OrOrExpression) $(D ||) $(GLINK AndAndExpression) ) $(DDOC_BLANKLINE ) $(P The result type of an $(I OrOrExpression) is $(D bool), unless the right operand has type $(D void), when the result is type $(D void). ) $(DDOC_BLANKLINE ) $(P The $(I OrOrExpression) evaluates its left operand. ) $(DDOC_BLANKLINE ) $(P If the left operand, converted to type $(D bool), evaluates to $(D true), then the right operand is not evaluated. If the result type of the $(I OrOrExpression) is $(D bool) then the result of the expression is $(D true). ) $(DDOC_BLANKLINE ) $(P If the left operand is $(D false), then the right operand is evaluated. If the result type of the $(I OrOrExpression) is $(D bool) then the result of the expression is the right operand converted to type $(D bool). ) $(DDOC_BLANKLINE )

$(LNAME2 andand_expressions, AndAnd Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME AndAndExpression): $(GLINK OrExpression) $(GSELF AndAndExpression) $(D $(AMP )$(AMP )) $(GLINK OrExpression) ) $(DDOC_BLANKLINE ) $(P The result type of an $(I AndAndExpression) is $(D bool), unless the right operand has type $(D void), when the result is type $(D void). ) $(DDOC_BLANKLINE ) $(P The $(I AndAndExpression) evaluates its left operand. ) $(DDOC_BLANKLINE ) $(P If the left operand, converted to type $(D bool), evaluates to $(D false), then the right operand is not evaluated. If the result type of the $(I AndAndExpression) is $(D bool) then the result of the expression is $(D false). ) $(DDOC_BLANKLINE ) $(P If the left operand is $(D true), then the right operand is evaluated. If the result type of the $(I AndAndExpression) is $(D bool) then the result of the expression is the right operand converted to type $(D bool). ) $(DDOC_BLANKLINE )

$(LNAME2 bitwise_expressions, Bitwise Expressions)

$(DDOC_BLANKLINE ) $(P Bit wise expressions perform a $(LINK2 https://en.wikipedia.org/wiki/Bitwise_operation, bitwise operation) on their operands. Their operands must be integral types. First, the $(DDSUBLINK spec/type, usual-arithmetic-conversions, Usual Arithmetic Conversions) are done. Then, the bitwise operation is done. ) $(DDOC_SEE_ALSO $(GLINK ShiftExpression), $(GLINK ComplementExpression)) $(DDOC_BLANKLINE ) $(PANEL $(NOTE If an OrExpression, XorExpression or AndExpression appears on either side of an EqualExpression, IdentityExpression or RelExpression, it is a compile error. Instead, disambiguate by using parentheses. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_FAIL $(D_CODE $(D_KEYWORD int) x, a, b; x = a & 5 == b; $(D_COMMENT // error )x = a & 5 $(D_KEYWORD is) b; $(D_COMMENT // error )x = a & 5 <= b; $(D_COMMENT // error ) x = (a & 5) == b; $(D_COMMENT // OK )x = a & (5 == b); $(D_COMMENT // OK )) ) ) $(DDOC_BLANKLINE )

$(LNAME2 or_expressions, Or Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME OrExpression): $(GLINK XorExpression) $(GSELF OrExpression) $(D |) $(GLINK XorExpression) ) $(DDOC_BLANKLINE ) $(P The operands are OR'd together.) $(DDOC_BLANKLINE )

$(LNAME2 xor_expressions, Xor Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME XorExpression): $(GLINK AndExpression) $(GSELF XorExpression) $(D ^) $(GLINK AndExpression) ) $(DDOC_BLANKLINE ) $(P The operands are XOR'd together.) $(DDOC_BLANKLINE )

$(LNAME2 and_expressions, And Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME AndExpression): $(GLINK CmpExpression) $(GSELF AndExpression) $(D &) $(GLINK CmpExpression) ) $(DDOC_BLANKLINE ) $(P The operands are AND'd together.) $(DDOC_BLANKLINE )

$(LNAME2 compare_expressions, Compare Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME CmpExpression): $(GLINK EqualExpression) $(GLINK IdentityExpression) $(GLINK RelExpression) $(GLINK InExpression) $(GLINK ShiftExpression) ) $(DDOC_BLANKLINE )

$(LNAME2 equality_expressions, Equality Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME EqualExpression): $(GLINK ShiftExpression) $(D ==) $(GLINK ShiftExpression) $(GLINK ShiftExpression) $(D !=) $(GLINK ShiftExpression) ) $(DDOC_BLANKLINE ) $(P Equality expressions compare the two operands for equality ($(D ==)) or inequality ($(D !=)). The type of the result is $(D bool). ) $(DDOC_BLANKLINE ) $(P Inequality is defined as the logical negation of equality.) $(DDOC_BLANKLINE ) $(P If the operands are integral values, the $(DDSUBLINK spec/type, usual-arithmetic-conversions, Usual Arithmetic Conversions) are applied to bring them to a common type before comparison. Equality is defined as the bit patterns of the common type match exactly. ) $(DDOC_BLANKLINE ) $(P If the operands are pointers, equality is defined as the bit patterns of the operands match exactly. ) $(DDOC_BLANKLINE ) $(P For float, double, and real values, the $(DDSUBLINK spec/type, usual-arithmetic-conversions, Usual Arithmetic Conversions) are applied to bring them to a common type before comparison. The values $(D -0) and $(D +0) are considered equal. If either or both operands are NaN, then $(D ==) returns false and $(D !=) returns $(D true). Otherwise, the bit patterns of the common type are compared for equality. ) $(DDOC_BLANKLINE ) $(P For static and dynamic arrays, equality is defined as the lengths of the arrays matching, and all the elements are equal. ) $(DDOC_BLANKLINE ) $(DDOC_DEPRECATED For complex numbers, equality is defined as equivalent to:) $(DDOC_BLANKLINE ) $(D_CODE x.re == y.re && x.im == y.im ) $(DDOC_BLANKLINE )

$(LNAME2 class_struct_equality, Class & Struct Equality)

$(DDOC_BLANKLINE ) $(P For struct objects, equality means the result of the $(LINK2 https://dlang.org/spec/operatoroverloading.html#equals, opEquals() member function). If an opEquals() is not provided, equality is defined as the logical product of all equality results of the corresponding object fields. ) $(DDOC_BLANKLINE ) $(IMPLEMENTATION_DEFINED The contents of any alignment gaps in the struct object.) $(DDOC_BLANKLINE ) $(BEST_PRACTICE If there are overlapping fields, which happens with unions, the default equality will compare each of the overlapping fields. An opEquals() can account for which of the overlapping fields contains valid data. An opEquals() can override the default behavior of floating point NaN values always comparing as unequal. Be careful using memcmp() to implement opEquals() if:) $(DDOC_BLANKLINE ) $(UL $(LI there are any alignment gaps) $(LI any fields have an opEquals()) $(LI there are any floating point fields that may contain NaN or -0 values) ) $(DDOC_BLANKLINE ) $(P For class and struct objects, the expression $(D (a == b)) is rewritten as $(D a.opEquals(b)), and $(D (a != b)) is rewritten as $(D !a.opEquals(b)). ) $(DDOC_BLANKLINE ) $(P For class objects, the $(D ==) and $(D !=) operators are intended to compare the contents of the objects, however an appropriate $(D opEquals) override must be defined for this to work. The default $(D opEquals) provided by the root $(D Object) class is equivalent to the $(D is) operator (see below). Comparing against $(D null) is invalid, as $(D null) has no contents. Use the $(D is) and $(D !is) operators instead.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD class) C; C c; $(D_KEYWORD if) (c == $(D_KEYWORD null)) $(D_COMMENT // error ) ... $(D_KEYWORD if) (c $(D_KEYWORD is) $(D_KEYWORD null)) $(D_COMMENT // ok ) ... ) $(DDOC_BLANKLINE )

$(LNAME2 identity_expressions, Identity Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME IdentityExpression): $(GLINK ShiftExpression) $(D is) $(GLINK ShiftExpression) $(GLINK ShiftExpression) $(D ! is) $(GLINK ShiftExpression) ) $(DDOC_BLANKLINE ) $(P The $(D is) operator compares for identity of expression values. To compare for nonidentity, use $(D e1 !is e2). The type of the result is $(D bool). The operands undergo the $(DDSUBLINK spec/type, usual-arithmetic-conversions, Usual Arithmetic Conversions) to bring them to a common type before comparison. ) $(DDOC_BLANKLINE ) $(P For class / interface objects, identity is defined as the object references being identical. Null class objects can be compared with is. Note that interface objects need not have the same reference of the class they were cast from. To test whether an interface shares a class instance with another interface / class value, cast both operands to Object before comparing with is. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD interface) I { $(D_KEYWORD void) g(); } $(D_KEYWORD interface) I1 : I { $(D_KEYWORD void) g1(); } $(D_KEYWORD interface) I2 : I { $(D_KEYWORD void) g2(); } $(D_KEYWORD interface) J : I1, I2 { $(D_KEYWORD void) h(); } $(D_KEYWORD class) C : J { $(D_KEYWORD override) $(D_KEYWORD void) g() { } $(D_KEYWORD override) $(D_KEYWORD void) g1() { } $(D_KEYWORD override) $(D_KEYWORD void) g2() { } $(D_KEYWORD override) $(D_KEYWORD void) h() { } } $(D_KEYWORD void) main() @safe { C c = $(D_KEYWORD new) C; I i1 = $(D_KEYWORD cast)(I1) c; I i2 = $(D_KEYWORD cast)(I2) c; $(D_KEYWORD assert)(i1 !$(D_KEYWORD is) i2); $(D_COMMENT // not identical ) $(D_KEYWORD assert)(c !$(D_KEYWORD is) i2); $(D_COMMENT // not identical ) $(D_KEYWORD assert)($(D_KEYWORD cast)(Object) i1 $(D_KEYWORD is) $(D_KEYWORD cast)(Object) i2); $(D_COMMENT // identical )} ) ) $(DDOC_BLANKLINE ) $(P For struct objects and floating point values, identity is defined as the bits in the operands being identical. ) $(DDOC_BLANKLINE ) $(P For static and dynamic arrays, identity of two arrays is given when both arrays refer to the same memory location and contain the same number of elements. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE Object o; $(D_KEYWORD assert)(o $(D_KEYWORD is) $(D_KEYWORD null)); $(D_KEYWORD auto) a = [1, 2]; $(D_KEYWORD assert)(a $(D_KEYWORD is) a[0..$]); $(D_KEYWORD assert)(a !$(D_KEYWORD is) a[0..1]); $(D_KEYWORD auto) b = [1, 2]; $(D_KEYWORD assert)(a !$(D_KEYWORD is) b); ) ) $(DDOC_BLANKLINE ) $(DDOC_DEPRECATED Use of is to compare static arrays by address and length is deprecated. To do so, use the slice operator and compare slices of the arrays instead; for example, a1[] is a2[].) $(DDOC_BLANKLINE ) $(P For other operand types, identity is defined as being the same as equality. ) $(DDOC_BLANKLINE ) $(P The identity operator $(D is) cannot be overloaded. ) $(DDOC_BLANKLINE )

$(LNAME2 relation_expressions, Relational Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME RelExpression): $(GLINK ShiftExpression) $(D <) $(GLINK ShiftExpression) $(GLINK ShiftExpression) $(D <=) $(GLINK ShiftExpression) $(GLINK ShiftExpression) $(D >) $(GLINK ShiftExpression) $(GLINK ShiftExpression) $(D >=) $(GLINK ShiftExpression) ) $(DDOC_BLANKLINE ) $(P First, the $(DDSUBLINK spec/type, usual-arithmetic-conversions, Usual Arithmetic Conversions) are done on the operands. The result type of a relational expression is $(D bool). ) $(DDOC_BLANKLINE )

$(LNAME2 array_comparisons, Array Comparisons)

$(DDOC_BLANKLINE ) $(P For static and dynamic arrays, the result of a CmpExpression is the result of the operator applied to the first non-equal element of the array. If two arrays compare equal, but are of different lengths, the shorter array compares as "less" than the longer array. ) $(DDOC_BLANKLINE )

$(LNAME2 integer_comparisons, Integer Comparisons)

$(DDOC_BLANKLINE ) $(P Integer comparisons happen when both operands are integral types. ) $(DDOC_BLANKLINE ) $(TABLE2 Integer comparison operators, Operator, Relation $(TROW $(D <), less) $(TROW $(D >), greater) $(TROW $(D <)$(D =), less or equal) $(TROW $(D >=), greater or equal) $(TROW $(D ==), equal) $(TROW $(D !=), not equal) ) $(DDOC_BLANKLINE ) $(P It is an error to have one operand be signed and the other unsigned for a $(D <), $(D <)$(D =), $(D >) or $(D >)$(D =) expression. Use $(RELATIVE_LINK2 cast_integers, casts) to make both operands signed or both operands unsigned. ) $(DDOC_BLANKLINE )

$(LEGACY_LNAME2 floating_point_comparisons, floating-point-comparisons, Floating Point Comparisons)

$(DDOC_BLANKLINE ) $(P If one or both operands are floating point, then a floating point comparison is performed. ) $(DDOC_BLANKLINE ) $(P A CmpExpression can have NaN operands. If either or both operands is NaN, the floating point comparison operation returns as follows:) $(DDOC_BLANKLINE ) $(TABLE2 Floating point comparison operators, Operator, Relation, Returns $(TROW $(D <),$(ARGS less), false) $(TROW $(D >),$(ARGS greater), false) $(TROW $(D <)$(D =),$(ARGS less or equal), false) $(TROW $(D >=),$(ARGS greater or equal), false) $(TROW $(D ==),equal, false) $(TROW $(D !=),$(ARGS unordered, less, or greater), true) ) $(DDOC_BLANKLINE ) $(BEST_PRACTICE Although IdentityExpression can be used to check for T.nan, there are other floating-point values for NaN produced at runtime. Use $(REF isNaN, std,math,traits) to handle all of them.) $(DDOC_BLANKLINE )

$(LEGACY_LNAME2 class_comparisons, class-comparisons, Class Comparisons)

$(DDOC_BLANKLINE ) $(P For class objects, EqualExpression and RelExpression compare the contents of the objects. Therefore, comparing against a $(CODE null) class reference is invalid, as $(CODE null) has no contents.) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD class) C {} $(D_KEYWORD void) fun() { C c; $(D_COMMENT //if $(LPAREN)c < null$(RPAREN ) {} // compile-time error ) $(D_KEYWORD assert)(c $(D_KEYWORD is) $(D_KEYWORD null)); $(D_KEYWORD if) (c > $(D_KEYWORD new) C) {} $(D_COMMENT // runtime error )} ) ) $(DDOC_BLANKLINE ) $(P For class objects, the result of Object.opCmp() forms the left operand, and 0 forms the right operand. The result of an EqualExpression or RelExpression (o1 op o2) is:) $(DDOC_BLANKLINE ) $(D_CODE (o1.opCmp(o2) op 0) ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 in_expressions, In Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME InExpression): $(GLINK ShiftExpression) $(D in) $(GLINK ShiftExpression) $(GLINK ShiftExpression) $(D ! in) $(GLINK ShiftExpression) ) $(DDOC_BLANKLINE ) $(P A container such as an associative array $(DDSUBLINK spec/hash-map, testing_membership, can be tested) to see if it contains a certain key:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD int) foo[string]; ... $(D_KEYWORD if) ($(D_STRING "hello") $(D_KEYWORD in) foo) { $(D_COMMENT // the string was found )} ) $(DDOC_BLANKLINE ) $(P The result of an $(I InExpression) is a pointer for associative arrays. The pointer is $(D null) if the container has no matching key. If there is a match, the pointer points to a value associated with the key. ) $(DDOC_BLANKLINE ) $(P The $(D !in) expression is the logical negation of the $(D in) operation. ) $(DDOC_BLANKLINE ) $(P The $(D in) expression has the same precedence as the relational expressions $(D <), $(D <)$(D =), etc.) $(DDOC_BLANKLINE ) $(NOTE When $(DDSUBLINK spec/operatoroverloading, binary, overloading) in, normally only $(TT opBinaryRight) would be defined. This is because the operation is usually not defined by the key type but by the container, which appears on the right hand side of the in operator.) $(DDOC_BLANKLINE )

$(LNAME2 shift_expressions, Shift Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME ShiftExpression): $(GLINK AddExpression) $(GSELF ShiftExpression) $(D <<) $(GLINK AddExpression) $(GSELF ShiftExpression) $(D >>) $(GLINK AddExpression) $(GSELF ShiftExpression) $(D >>>) $(GLINK AddExpression) ) $(DDOC_BLANKLINE ) $(P The operands must be integral types, and undergo the $(DDSUBLINK spec/type, integer-promotions, Integer Promotions). The result type is the type of the left operand after the promotions. The result value is the result of shifting the bits by the right operand's value. ) $(DDOC_BLANKLINE ) $(UL $(LI $(D <)$(D <) is a left shift.) $(LI $(D >)$(D >) is a signed right shift.) $(LI $(D >)$(D >)$(D >) is an unsigned right shift.) ) $(DDOC_BLANKLINE ) $(IMPLEMENTATION_DEFINED The result of a shift by a negative value or by the same or more bits than the size of the quantity being shifted is undefined. When the shift amount is known at compile time, doing this results in a compile error. $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD int) c; $(D_KEYWORD int) s = -3; $(D_KEYWORD auto) y = c << s; $(D_COMMENT // implementation defined value ) $(D_KEYWORD auto) x = c << 33; $(D_COMMENT // error, max shift count allowed is 31 )) ) $(DDOC_BLANKLINE )

$(LNAME2 additive_expressions, Additive Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME AddExpression): $(GLINK MulExpression) $(GSELF AddExpression) $(D +) $(GLINK MulExpression) $(GSELF AddExpression) $(D -) $(GLINK MulExpression) $(GSELF AddExpression) $(D ~) $(GLINK MulExpression) ) $(DDOC_BLANKLINE )

$(LNAME2 add_expressions, Add Expressions)

$(P In the cases of the Additive operations $(D +) and $(D -): ) $(DDOC_BLANKLINE ) $(P If the operands are of integral types, they undergo the $(DDSUBLINK spec/type, usual-arithmetic-conversions, Usual Arithmetic Conversions), and then are brought to a common type using the $(DDSUBLINK spec/type, usual-arithmetic-conversions, Usual Arithmetic Conversions). ) $(DDOC_BLANKLINE ) $(P If both operands are of integral types and an overflow or underflow occurs in the computation, wrapping will happen. For example:) $(UL $(LI $(D uint.max + 1 == uint.min)) $(LI $(D uint.min - 1 == uint.max)) $(LI $(D int.max + 1 == int.min)) $(LI $(D int.min - 1 == int.max)) ) $(DDOC_BLANKLINE ) $(P If either operand is a floating point type, the other is implicitly converted to floating point and they are brought to a common type via the $(DDSUBLINK spec/type, usual-arithmetic-conversions, Usual Arithmetic Conversions). ) $(DDOC_BLANKLINE ) $(P Add expressions for floating point operands are not associative. ) $(DDOC_BLANKLINE )

$(LNAME2 pointer_arithmetic, Pointer Arithmetic)

$(DDOC_BLANKLINE ) $(P If the first operand is a pointer, and the second is an integral type, the resulting type is the type of the first operand, and the resulting value is the pointer plus (or minus) the second operand multiplied by the size of the type pointed to by the first operand. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD int)[] a = [1,2,3]; $(D_KEYWORD int)* p = a.ptr; $(D_KEYWORD assert)(*p == 1); *(p + 2) = 4; $(D_COMMENT // same as `p[2] = 4` )$(D_KEYWORD assert)(a[2] == 4); ) ) $(DDOC_BLANKLINE ) $(P $(GLINK IndexOperation) can also be used with a pointer and has the same behaviour as adding an integer, then dereferencing the result.) $(DDOC_BLANKLINE ) $(P If the second operand is a pointer, and the first is an integral type, and the operator is $(D +), the operands are reversed and the pointer arithmetic just described is applied. ) $(DDOC_BLANKLINE ) $(P Producing a pointer through pointer arithmetic is not allowed in $(DDLINK spec/memory-safe-d, Memory-Safe-D-Spec, @safe) code.) $(DDOC_BLANKLINE ) $(P If both operands are pointers, and the operator is $(D +), then it is illegal. ) $(DDOC_BLANKLINE ) $(P If both operands are pointers, and the operator is $(D -), the pointers are subtracted and the result is divided by the size of the type pointed to by the operands. In this calculation the assumed size of $(D void) is one byte. It is an error if the pointers point to different types. The type of the result is $(D ptrdiff_t). ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD int)[] a = [1,2,3]; ptrdiff_t d = &a[2] - a.ptr; $(D_KEYWORD assert)(d == 2); ) ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 cat_expressions, Cat Expressions)

$(P In the case of the Additive operation $(D ~): ) $(DDOC_BLANKLINE ) $(P A $(I CatExpression) concatenates a container's data with other data, producing a new container.) $(DDOC_BLANKLINE ) $(P For a dynamic array, the other operand must either be another array or a single value that implicitly converts to the element type of the array. See $(DDSUBLINK spec/arrays, array-concatenation, Array Concatenation).) $(DDOC_BLANKLINE )

$(LNAME2 mul_expressions, Mul Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME MulExpression): $(GLINK UnaryExpression) $(GSELF MulExpression) $(D *) $(GLINK UnaryExpression) $(GSELF MulExpression) $(D /) $(GLINK UnaryExpression) $(GSELF MulExpression) $(D %) $(GLINK UnaryExpression) ) $(DDOC_BLANKLINE ) $(P The operands must be arithmetic types. They undergo the $(DDSUBLINK spec/type, usual-arithmetic-conversions, Usual Arithmetic Conversions). ) $(DDOC_BLANKLINE ) $(P For integral operands, the $(D *), $(D /), and $(D %) correspond to multiply, divide, and modulus operations. For multiply, overflows are ignored and simply chopped to fit into the integral type. ) $(DDOC_BLANKLINE )

$(LNAME2 division, Division)

$(DDOC_BLANKLINE ) $(P For integral operands of the $(D /) and $(D %) operators, the quotient rounds towards zero and the remainder has the same sign as the dividend. ) $(DDOC_BLANKLINE ) $(P The following divide or modulus integral operands:) $(DDOC_BLANKLINE ) $(UL $(LI denominator is 0) $(LI signed int.min is the numerator and -1 is the denominator) $(LI signed long.min is the numerator and -1L is the denominator) ) $(DDOC_BLANKLINE ) $(P are illegal if encountered during Compile Time Execution.) $(DDOC_BLANKLINE ) $(UNDEFINED_BEHAVIOR is exhibited if they are encountered during run time. $(LINK2 https://dlang.org/phobos/core_checkedint.html, core.checkedint) can be used to check for them and select a defined behavior. ) $(DDOC_BLANKLINE )

$(LNAME2 mul_floating, Floating Point)

$(DDOC_BLANKLINE ) $(P For floating point operands, the * and / operations correspond to the IEEE 754 floating point equivalents. % is not the same as the IEEE 754 remainder. For example, 15.0 % 10.0 == 5.0, whereas for IEEE 754, remainder(15.0,10.0) == -5.0. ) $(DDOC_BLANKLINE ) $(P Mul expressions for floating point operands are not associative. ) $(DDOC_BLANKLINE )

$(LEGACY_LNAME2 UnaryExpression, unary-expression, Unary Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME UnaryExpression): $(D $(AMP )) $(GSELF UnaryExpression) $(D ++) $(GSELF UnaryExpression) $(D --) $(GSELF UnaryExpression) $(D *) $(GSELF UnaryExpression) $(D -) $(GSELF UnaryExpression) $(D +) $(GSELF UnaryExpression) $(D !) $(GSELF UnaryExpression) $(GLINK ComplementExpression) $(GLINK DeleteExpression) $(GLINK CastExpression) $(GLINK ThrowExpression) $(GLINK PowExpression) ) $(DDOC_BLANKLINE ) $(TABLE Operator, Description $(TROW &, Take memory address of an $(RELATIVE_LINK2 .define-lvalue, lvalue) - see $(DDSUBLINK spec/type, pointers, pointers)) $(TROW ++, Increment before use - see $(RELATIVE_LINK2 order-of-evaluation, order of evaluation)) $(TROW --, Decrement before use) $(TROW *, Dereference/indirection - typically for pointers) $(TROW -, Negative) $(TROW +, Positive) $(TROW !, Logical NOT) ) $(DDOC_BLANKLINE ) $(P The usual $(DDSUBLINK spec/type, integer-promotions, Integer Promotions) are performed prior to unary - and + operations.) $(DDOC_BLANKLINE )

$(LNAME2 complement_expressions, Complement Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME ComplementExpression): $(D ~) $(GLINK UnaryExpression) ) $(DDOC_BLANKLINE ) $(P $(I ComplementExpression)s work on integral types (except $(D bool)). All the bits in the value are complemented. The usual $(DDSUBLINK spec/type, integer-promotions, Integer Promotions) are performed prior to the complement operation. ) $(DDOC_BLANKLINE )

$(LNAME2 delete_expressions, Delete Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME DeleteExpression): $(D delete) $(GLINK UnaryExpression) ) $(DDOC_DEPRECATED delete has been deprecated. Instead, please use $(REF1 destroy, object) if feasible, or $(REF __delete, core, memory) as a last resort.) $(DDOC_BLANKLINE ) $(P If the $(I UnaryExpression) is a class object reference, and there is a destructor for that class, the destructor is called for that object instance. ) $(DDOC_BLANKLINE ) $(P Next, if the $(I UnaryExpression) is a class object reference, or a pointer to a struct instance, and the class or struct has overloaded operator delete, then that operator delete is called for that class object instance or struct instance. ) $(DDOC_BLANKLINE ) $(P Otherwise, the garbage collector is called to immediately free the memory allocated for the class instance or struct instance. ) $(DDOC_BLANKLINE ) $(P If the $(I UnaryExpression) is a pointer or a dynamic array, the garbage collector is called to immediately release the memory. ) $(DDOC_BLANKLINE ) $(P The pointer, dynamic array, or reference is set to $(D null) after the delete is performed. Any attempt to reference the data after the deletion via another reference to it will result in undefined behavior. ) $(DDOC_BLANKLINE ) $(P If $(I UnaryExpression) is a variable allocated on the stack, the class destructor (if any) is called for that instance. The garbage collector is not called. ) $(DDOC_BLANKLINE ) $(UNDEFINED_BEHAVIOR $(OL $(LI Using delete to free memory not allocated by the garbage collector.) $(LI Referring to data that has been the operand of delete.) )) $(DDOC_BLANKLINE )

$(LNAME2 cast_expressions, Cast Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME CastExpression): $(D cast $(LPAREN)) $(GLINK2 type, Type) $(D $(RPAREN )) $(GLINK UnaryExpression) $(GLINK CastQual) ) $(DDOC_BLANKLINE ) $(P A $(I CastExpression) converts the $(I UnaryExpression) to $(I Type).) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD cast)(foo) -p; $(D_COMMENT // cast $(LPAREN)-p$(RPAREN ) to type foo )(foo) - p; $(D_COMMENT // subtract p from foo )) $(DDOC_BLANKLINE )

$(LNAME2 cast_basic_data_types, Basic Data Types)

$(P For situations where $(DDSUBLINK spec/type, implicit-conversions, implicit conversions) on basic types cannot be performed, the type system may be forced to accept the reinterpretation of a memory region by using a cast. ) $(DDOC_BLANKLINE ) $(P An example of such a scenario is represented by trying to store a wider type into a narrower one: ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD int) a; $(D_KEYWORD byte) b = a; $(D_COMMENT // cannot implicitly convert expression a of type int to byte )) $(DDOC_BLANKLINE ) $(P When casting a source type that is wider than the destination type, the value is truncated to the destination size. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD int) a = 64389; $(D_COMMENT // 00000000 00000000 11111011 10000101 )$(D_KEYWORD byte) b = $(D_KEYWORD cast)($(D_KEYWORD byte)) a; $(D_COMMENT // 10000101 )$(D_KEYWORD ubyte) c = $(D_KEYWORD cast)($(D_KEYWORD ubyte)) a; $(D_COMMENT // 10000101 )$(D_KEYWORD short) d = $(D_KEYWORD cast)($(D_KEYWORD short)) a; $(D_COMMENT // 11111011 10000101 )$(D_KEYWORD ushort) e = $(D_KEYWORD cast)($(D_KEYWORD ushort)) a; $(D_COMMENT // 11111011 10000101 ) writeln(b); writeln(c); writeln(d); writeln(e); ) ) $(DDOC_BLANKLINE ) $(P For integral types casting from a narrower type to a wider type is done by performing sign extension. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD ubyte) a = 133; $(D_COMMENT // 10000101 )$(D_KEYWORD byte) b = a; $(D_COMMENT // 10000101 ) writeln(a); writeln(b); $(D_KEYWORD ushort) c = a; $(D_COMMENT // 00000000 10000101 )$(D_KEYWORD short) d = b; $(D_COMMENT // 11111111 10000101 ) writeln(c); writeln(d); ) ) $(DDOC_BLANKLINE )

$(LNAME2 cast_class, Class References)

$(DDOC_BLANKLINE ) $(P Any casting of a class reference to a derived class reference is done with a runtime check to make sure it really is a downcast. $(D null) is the result if it isn't. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD class) A {} $(D_KEYWORD class) B : A {} $(D_KEYWORD void) main() { A a = $(D_KEYWORD new) A; $(D_COMMENT //B b = a; // error, need cast ) B b = $(D_KEYWORD cast)(B) a; $(D_COMMENT // b is null if a is not a B ) $(D_KEYWORD assert)(b $(D_KEYWORD is) $(D_KEYWORD null)); a = b; $(D_COMMENT // no cast needed ) a = $(D_KEYWORD cast)(A) b; $(D_COMMENT // no runtime check needed for upcast ) $(D_KEYWORD assert)(a $(D_KEYWORD is) b); } ) ) $(DDOC_BLANKLINE ) $(P In order to determine if an object $(D o) is an instance of a class $(D B) use a cast:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD if) ($(D_KEYWORD cast)(B) o) { $(D_COMMENT // o is an instance of B )} $(D_KEYWORD else) { $(D_COMMENT // o is not an instance of B )} ) $(DDOC_BLANKLINE ) $(P Casting a pointer type to and from a class type is done as a type paint (i.e. a reinterpret cast). ) $(DDOC_BLANKLINE )

$(LNAME2 cast_pointers, Pointers)

$(P Casting a pointer variable to another pointer type modifies the value that will be obtained as a result of dereferencing, along with the number of bytes on which pointer arithmetic is performed. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD int) val = 25185; $(D_COMMENT // 00000000 00000000 01100010 01100001 )$(D_KEYWORD char) *ch = $(D_KEYWORD cast)($(D_KEYWORD char)*)(&val); writeln(*ch); $(D_COMMENT // a )writeln($(D_KEYWORD cast)($(D_KEYWORD int))(*ch)); $(D_COMMENT // 97 )writeln(*(ch + 1)); $(D_COMMENT // b )writeln($(D_KEYWORD cast)($(D_KEYWORD int))(*(ch + 1))); $(D_COMMENT // 98 )) ) $(DDOC_BLANKLINE ) $(P Similarly, when casting a dynamically allocated array to a type of smaller size, the bytes of the initial array will be divided and regrouped according to the new dimension. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD import) core.stdc.stdlib; $(D_KEYWORD int) *p = $(D_KEYWORD cast)($(D_KEYWORD int)*) malloc(5 * $(D_KEYWORD int).sizeof); $(D_KEYWORD for) ($(D_KEYWORD int) i = 0; i < 5; i++) { p[i] = i + 'a'; } $(D_COMMENT // p = [97, 98, 99, 100, 101] ) $(D_KEYWORD char)* c = $(D_KEYWORD cast)($(D_KEYWORD char)*) p; $(D_COMMENT // c = [97, 0, 0, 0, 98, 0, 0, 0, 99 ...] )$(D_KEYWORD for) ($(D_KEYWORD int) i = 0; i < 5 * $(D_KEYWORD int).sizeof; i++) { writeln(c[i]); } ) ) $(DDOC_BLANKLINE ) $(P When casting a pointer of type A to a pointer of type B and type B is wider than type A, attempts at accessing the memory exceeding the size of A will result in undefined behaviour. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD char) c = 'a'; $(D_KEYWORD int) *p = $(D_KEYWORD cast)($(D_KEYWORD int)*) (&c); writeln(*p); ) ) $(DDOC_BLANKLINE ) $(P It is also possible to cast pointers to basic data types. A common practice could be to cast the pointer to an int value and then print its address: ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD import) core.stdc.stdlib; $(D_KEYWORD int) *p = $(D_KEYWORD cast)($(D_KEYWORD int)*) malloc($(D_KEYWORD int).sizeof); $(D_KEYWORD int) a = $(D_KEYWORD cast)($(D_KEYWORD int)) p; writeln(a); ) ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 cast_array, Arrays)

$(DDOC_BLANKLINE ) $(P Casting a dynamic array to another dynamic array is done only if the array lengths multiplied by the element sizes match. The cast is done as a type paint, with the array length adjusted to match any change in element size. If there's not a match, a runtime error is generated.) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD byte)[] a = [1,2,3]; $(D_COMMENT //auto b = cast$(LPAREN)int[]$(RPAREN )a; // runtime error: array cast misalignment ) $(D_KEYWORD int)[] c = [1, 2, 3]; $(D_KEYWORD auto) d = $(D_KEYWORD cast)($(D_KEYWORD byte)[])c; $(D_COMMENT // ok )$(D_COMMENT // prints: )$(D_COMMENT // [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0] )writeln(d); ) ) $(DDOC_BLANKLINE ) $(DDOC_SEE_ALSO $(RELATIVE_LINK2 cast_array_literal, Casting array literals).) $(DDOC_BLANKLINE )

$(LNAME2 cast_static_array, Static Arrays)

$(DDOC_BLANKLINE ) $(P Casting a static array to another static array is done only if the array lengths multiplied by the element sizes match; a mismatch is illegal. The cast is done as a type paint (aka a reinterpret cast). The contents of the array are not changed.) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD byte)[16] b = 3; $(D_COMMENT // set each element to 3 )$(D_KEYWORD assert)(b[0] == 0x03); $(D_KEYWORD int)[4] ia = $(D_KEYWORD cast)($(D_KEYWORD int)[4]) b; $(D_COMMENT // print elements as hex )$(D_KEYWORD foreach) (i; ia) writefln($(D_STRING "%x"), i); $(D_COMMENT /* prints: 3030303 3030303 3030303 3030303 */) ) ) $(DDOC_BLANKLINE )

$(LNAME2 cast_integers, Integers)

$(DDOC_BLANKLINE ) $(P Casting an integer to a smaller integral will truncate the value towards the least significant bits. If the target type is signed and the most significant bit is set after truncation, that bit will be lost from the value and the sign bit will be set.) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD uint) a = 260; $(D_KEYWORD auto) b = $(D_KEYWORD cast)($(D_KEYWORD ubyte)) a; $(D_KEYWORD assert)(b == 4); $(D_COMMENT // truncated like 260 & 0xff ) $(D_KEYWORD int) c = 128; $(D_KEYWORD assert)($(D_KEYWORD cast)($(D_KEYWORD byte))c == -128); $(D_COMMENT // reinterpreted )) ) $(DDOC_BLANKLINE ) $(P Converting between signed and unsigned types will reinterpret the value if the destination type cannot represent the source value.) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD short) c = -1; $(D_KEYWORD ushort) d = c; $(D_KEYWORD assert)(d == $(D_KEYWORD ushort).max); $(D_KEYWORD assert)($(D_KEYWORD uint)(c) == $(D_KEYWORD uint).max); $(D_KEYWORD ubyte) e = 255; $(D_KEYWORD byte) f = e; $(D_KEYWORD assert)(f == -1); $(D_COMMENT // reinterpreted )$(D_KEYWORD assert)($(D_KEYWORD short)(e) == 255); $(D_COMMENT // no change )) ) $(DDOC_BLANKLINE )

$(LNAME2 cast_floating, Floating Point)

$(DDOC_BLANKLINE ) $(P Casting a floating point literal from one type to another changes its type, but internally it is retained at full precision for the purposes of constant folding.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD void) test() { $(D_KEYWORD real) a = 3.40483L; $(D_KEYWORD real) b; b = 3.40483; $(D_COMMENT // literal is not truncated to double precision ) $(D_KEYWORD assert)(a == b); $(D_KEYWORD assert)(a == 3.40483); $(D_KEYWORD assert)(a == 3.40483L); $(D_KEYWORD assert)(a == 3.40483F); $(D_KEYWORD double) d = 3.40483; $(D_COMMENT // truncate literal when assigned to variable ) $(D_KEYWORD assert)(d != a); $(D_COMMENT // so it is no longer the same ) $(D_KEYWORD const) $(D_KEYWORD double) x = 3.40483; $(D_COMMENT // assignment to const is not ) $(D_KEYWORD assert)(x == a); $(D_COMMENT // truncated if the initializer is visible )} ) $(DDOC_BLANKLINE ) $(P Casting a floating point value to an integral type is the equivalent of converting to an integer using truncation. If the floating point value is outside the range of the integral type, the cast will produce an invalid result (this is also the case in C, C++).) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD void) main() { $(D_KEYWORD int) a = $(D_KEYWORD cast)($(D_KEYWORD int)) 0.8f; $(D_KEYWORD assert)(a == 0); $(D_KEYWORD long) b = $(D_KEYWORD cast)($(D_KEYWORD long)) 1.5; $(D_KEYWORD assert)(b == 1L); $(D_KEYWORD long) c = $(D_KEYWORD cast)($(D_KEYWORD long)) -1.5; $(D_KEYWORD assert)(c == -1); $(D_COMMENT // if the float overflows, the cast returns the integer value of ) $(D_COMMENT // 80000000_00000000H $(LPAREN)64-bit operand$(RPAREN ) or 80000000H $(LPAREN)32-bit operand$(RPAREN ) ) $(D_KEYWORD long) d = $(D_KEYWORD cast)($(D_KEYWORD long)) $(D_KEYWORD float).max; $(D_KEYWORD assert)(d == $(D_KEYWORD long).min); $(D_KEYWORD int) e = $(D_KEYWORD cast)($(D_KEYWORD int)) (1234.5 + $(D_KEYWORD int).max); $(D_KEYWORD assert)(e == $(D_KEYWORD int).min); $(D_COMMENT // for types represented on 16 or 8 bits, the result is the same as ) $(D_COMMENT // 32-bit types, but the most significant bits are ignored ) $(D_KEYWORD short) f = $(D_KEYWORD cast)($(D_KEYWORD short)) $(D_KEYWORD float).max; $(D_KEYWORD assert)(f == 0); } ) $(DDOC_BLANKLINE )

$(LNAME2 cast_struct, Structs)

$(DDOC_BLANKLINE ) $(P Casting a value $(I v) to a struct $(I S), when value is not a struct of the same type, is equivalent to:) $(DDOC_BLANKLINE ) $(D_CODE S(v) ) $(DDOC_BLANKLINE )

$(LNAME2 cast_qualifier, Qualifier Cast)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME CastQual): $(D cast $(LPAREN)) $(GLINK2 type, TypeCtors)$(OPT ) $(D $(RPAREN )) $(GLINK UnaryExpression) ) $(DDOC_BLANKLINE ) $(P A $(I CastQual) replaces the qualifiers in the type of the $(I UnaryExpression):) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD shared) $(D_KEYWORD int) x; $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)($(D_KEYWORD typeof)($(D_KEYWORD cast)($(D_KEYWORD const))x) == $(D_KEYWORD const) $(D_KEYWORD int))); ) ) $(DDOC_BLANKLINE ) $(P Casting with no type or qualifiers removes any top level $(D const), $(D immutable), $(D shared) or $(D inout) type modifiers from the type of the $(I UnaryExpression).) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD shared) $(D_KEYWORD int) x; $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)($(D_KEYWORD typeof)($(D_KEYWORD cast)()x) == $(D_KEYWORD int))); ) ) $(DDOC_BLANKLINE )

$(LNAME2 cast_void, Casting to void)

$(DDOC_BLANKLINE ) $(P Casting an expression to $(D void) type is allowed to mark that the result is unused. On $(GLINK2 statement, ExpressionStatement), it could be used properly to avoid a "has no effect" error.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD void) foo($(D_KEYWORD lazy) $(D_KEYWORD void) exp) {} $(D_KEYWORD void) main() { foo(10); $(D_COMMENT // NG - expression '10' has no effect ) foo($(D_KEYWORD cast)($(D_KEYWORD void))10); $(D_COMMENT // OK )} ) $(DDOC_BLANKLINE )

$(LNAME2 throw_expression, Throw Expression)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME ThrowExpression): $(D throw) $(GLINK AssignExpression) ) $(DDOC_BLANKLINE ) $(P $(I AssignExpression) is evaluated and must yield a reference to a Throwable or a class derived from Throwable. The reference is thrown as an exception, interrupting the current control flow to continue at a suitable $(D catch) clause of a $(GLINK2 statement, try-statement). This process will execute any applicable $(LINK2 statement.html#ScopeGuardStatement, scope (exit) / scope (failure)) passed since entering the corresponding try block. ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD throw) $(D_KEYWORD new) Exception($(D_STRING "message")); ) $(DDOC_BLANKLINE ) $(P The Throwable must not be a qualified as immutable, const, inout or shared. The runtime may modify a thrown object (e.g. to contain a stack trace) which would violate const or immutable objects. ) $(P A $(I ThrowExpression) may be nested in another expression: ) $(D_CODE $(D_KEYWORD void) foo($(D_KEYWORD int) $(D_KEYWORD function)() f) {} $(D_KEYWORD void) main() { foo(() => $(D_KEYWORD throw) $(D_KEYWORD new) Exception()); } ) $(DDOC_BLANKLINE ) $(P The type of a ThrowExpression is $(DDSUBLINK spec/type, noreturn, noreturn).) $(DDOC_BLANKLINE ) $(BEST_PRACTICE Use $(DDSUBLINK spec/expression, assert_expressions, Assert Expressions) rather than $(LINK2 $(ROOT_DIR )library/object#.Error, Error) to report program bugs and abort the program. ) $(DDOC_BLANKLINE )

$(LNAME2 pow_expressions, Pow Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME PowExpression): $(GLINK PostfixExpression) $(GLINK PostfixExpression) $(D ^^) $(GLINK UnaryExpression) ) $(DDOC_BLANKLINE ) $(P $(I PowExpression) raises its left operand to the power of its right operand. ) $(DDOC_BLANKLINE )

$(LNAME2 postfix_expressions, Postfix Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME PostfixExpression): $(GLINK PrimaryExpression) $(GSELF PostfixExpression) $(D .) $(GLINK_LEX Identifier) $(GSELF PostfixExpression) $(D .) $(GLINK2 template, TemplateInstance) $(GSELF PostfixExpression) $(D .) $(GLINK NewExpression) $(GSELF PostfixExpression) $(D ++) $(GSELF PostfixExpression) $(D --) $(GSELF PostfixExpression) $(D $(LPAREN)) $(GLINK NamedArgumentList)$(OPT ) $(D $(RPAREN )) $(GLINK2 type, TypeCtors)$(OPT ) $(GLINK2 type, BasicType) $(D $(LPAREN)) $(GLINK NamedArgumentList)$(OPT ) $(D $(RPAREN )) $(GSELF PostfixExpression) $(GLINK IndexOperation) $(GSELF PostfixExpression) $(GLINK SliceOperation) ) $(DDOC_BLANKLINE ) $(TABLE Operator, Description $(TROW ., Either: $(UL $(LI Access a $(DDLINK spec/property, Properties, property) of a type or expression.) $(LI Access a member of a module, package, aggregate type or instance, enum or template instance.) $(LI Call a free function using $(DDSUBLINK spec/function, pseudo-member, UFCS).) ) ) $(TROW ++, Increment after use - see $(RELATIVE_LINK2 order-of-evaluation, order of evaluation)) $(TROW --, Decrement after use) $(TROW IndexOperation, Select a single element) $(TROW SliceOperation, Select a series of elements) ) $(DDOC_BLANKLINE )

$(LNAME2 argument-list, Postfix Argument Lists)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME ArgumentList): $(GLINK AssignExpression) $(GLINK AssignExpression) $(D ,) $(GLINK AssignExpression) $(D ,) $(GSELF ArgumentList) $(DDOC_BLANKLINE ) $(GNAME NamedArgumentList): $(GLINK NamedArgument) $(GLINK NamedArgument) $(D ,) $(GLINK NamedArgument) $(D ,) $(I NamedArgumentList) $(DDOC_BLANKLINE ) $(GNAME NamedArgument): $(GLINK_LEX Identifier) $(D :) $(GLINK AssignExpression) $(GLINK AssignExpression) ) $(DDOC_BLANKLINE ) $(P A callable expression can precede a list of arguments in parentheses.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD void) f($(D_KEYWORD int), $(D_KEYWORD int)); f(5, 6); (&f)(5, 6); ) $(DDOC_BLANKLINE ) $(P A type can precede a list of arguments.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD struct) S { $(D_KEYWORD int) x, y; } S s = S(1, 2); ) $(DDOC_BLANKLINE ) $(P See also: $(RELATIVE_LINK2 uniform_construction_syntax, Uniform construction syntax for built-in scalar types)) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LEGACY_LNAME2 index_operations, index_expressions, Index Operations)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME IndexOperation): $(D [) $(GLINK ArgumentList) $(D ]) ) $(DDOC_BLANKLINE ) $(P The base $(I PostfixExpression) is evaluated. The special variable $ is declared and set to be the number of elements in the base $(I PostfixExpression) (when available). A new declaration scope is created for the evaluation of the $(I ArgumentList) and $ appears in that scope only. ) $(DDOC_BLANKLINE ) $(P If the $(I PostfixExpression) is an expression of static or dynamic array type, the result of the indexing is an lvalue of the ith element in the array, where i is an integer evaluated from $(I ArgumentList). If $(I PostfixExpression) is a pointer p, the result is *(p + i) (see $(RELATIVE_LINK2 pointer_arithmetic, Pointer Arithmetic)). ) $(DDOC_BLANKLINE ) $(P If the base $(I PostfixExpression) is a $(DDSUBLINK spec/template, variadic-templates, $(I ValueSeq)) then the $(I ArgumentList) must consist of only one argument, and that must be statically evaluatable to an integral constant. That integral constant $(I n) then selects the $(I n)th expression in the $(I ValueSeq), which is the result of the $(I IndexOperation). It is an error if $(I n) is out of bounds of the $(I ValueSeq). ) $(DDOC_BLANKLINE ) $(P The index operator can be $(DDSUBLINK spec/operatoroverloading, array, overloaded). Using multiple indices in ArgumentList is only supported for operator overloading.) $(DDOC_BLANKLINE )

$(LEGACY_LNAME2 slice_operations, slice_expressions, Slice Operations)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME SliceOperation): $(D [ ]) $(D [) $(GLINK Slice) $(D ,)$(OPT ) $(D ]) $(DDOC_BLANKLINE ) $(GNAME Slice): $(GLINK AssignExpression) $(GLINK AssignExpression) $(D ,) $(GSELF Slice) $(GLINK AssignExpression) $(D ..) $(GLINK AssignExpression) $(GLINK AssignExpression) $(D ..) $(GLINK AssignExpression) $(D ,) $(GSELF Slice) ) $(DDOC_BLANKLINE ) $(P The base $(I PostfixExpression) is evaluated. The special variable $ is declared and set to be the number of elements in the $(I PostfixExpression) (when available). A new declaration scope is created for the evaluation of the $(I AssignExpression)..$(I AssignExpression) and $ appears in that scope only. ) $(DDOC_BLANKLINE ) $(P If the base $(I PostfixExpression) is a static or dynamic array a, the result of the slice is a dynamic array referencing elements a[i] to a[j-1] inclusive, where i and j are integers evaluated from the first and second $(I AssignExpression) respectively. ) $(DDOC_BLANKLINE ) $(P If the base $(I PostfixExpression) is a pointer p, the result will be a dynamic array referencing elements from p[i] to p[j-1] inclusive, where i and j are integers evaluated from the first and second $(I AssignExpression) respectively. ) $(DDOC_BLANKLINE ) $(P If the base $(I PostfixExpression) is a $(DDSUBLINK spec/template, variadic-templates, $(I ValueSeq)), then the result of the slice is a new $(I ValueSeq) formed from the upper and lower bounds, which must statically evaluate to integral constants. It is an error if those bounds are out of range. ) $(DDOC_BLANKLINE ) $(P The first $(I AssignExpression) is taken to be the inclusive lower bound of the slice, and the second $(I AssignExpression) is the exclusive upper bound. The result of the expression is a slice of the elements in $(I PostfixExpression). ) $(DDOC_BLANKLINE ) $(P If the $(D [ ]) form is used, the slice is of all the elements in the base $(I PostfixExpression). The base expression cannot be a pointer. ) $(DDOC_BLANKLINE ) $(P The slice operator can be $(DDSUBLINK spec/operatoroverloading, slice, overloaded). Using more than one Slice is only supported for operator overloading.) $(DDOC_BLANKLINE ) $(P A $(I SliceOperation) is not a modifiable lvalue.) $(DDOC_BLANKLINE )

$(LNAME2 slice_to_static_array, Slice Conversion to Static Array)

$(DDOC_BLANKLINE ) $(P If the slice bounds can be known at compile time, the slice expression may be implicitly convertible to a static array lvalue. For example:) $(DDOC_BLANKLINE ) $(D_CODE arr[a .. b] $(D_COMMENT // typed T[] )) $(DDOC_BLANKLINE ) $(P If both $(CODE a) and $(CODE b) are integers (which may be constant-folded), the slice expression can be converted to a static array of type $(D T[b - a]). ) $(NOTE a static array can also be $(DDSUBLINK spec/arrays, assignment, assigned from a slice), performing a runtime check that the lengths match.) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD void) f($(D_KEYWORD int)[2] sa) {} $(D_KEYWORD int)[] arr = [1, 2, 3]; $(D_KEYWORD void) test() { $(D_COMMENT //f$(LPAREN)arr$(RPAREN ); // error, can't convert ) f(arr[1 .. 3]); $(D_COMMENT // OK ) $(D_COMMENT //f$(LPAREN)arr[0 .. 3]$(RPAREN ); // error ) $(D_KEYWORD int)[2] g() { $(D_KEYWORD return) arr[0 .. 2]; } } ) ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD void) bar($(D_KEYWORD ref) $(D_KEYWORD int)[2] a) { $(D_KEYWORD assert)(a == [2, 3]); a = [4, 5]; } $(D_KEYWORD void) main() { $(D_KEYWORD int)[] arr = [1, 2, 3]; $(D_COMMENT // slicing an lvalue gives an lvalue ) bar(arr[1 .. 3]); $(D_KEYWORD assert)(arr == [1, 4, 5]); } ) ) $(DDOC_BLANKLINE ) $(COMMENT Not implemented yet - https://issues.dlang.org/show_bug.cgi?id=13700 $(P Certain other forms of slice expression can be implicitly converted to a static array when the slice length can be known at compile-time.) $(DDOC_BLANKLINE ) $(COMMENT SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD int)[] da = [1, 2, 3]; $(D_KEYWORD int) i = da[0]; $(D_COMMENT // runtime variable ) $(D_KEYWORD int)[2] f() { $(D_KEYWORD return) da[i .. i + 2]; } $(D_KEYWORD assert)(f() == [2, 3]); ) ) $(DDOC_BLANKLINE ) $(P The table below shows all the forms recognized:) $(DDOC_BLANKLINE ) $(DL $(DT $(D e)) $(DD An expression that contains no side effects.) $(DT $(D a), $(D b)) $(DD Integers (that may be constant-folded).) ) $(DDOC_BLANKLINE ) $(TABLE2 , Form, The length calculated at compile time $(TROW $(D arr[]), The compile time length of $(D arr) if it's known.) $(TROW $(D arr[a .. b]), $(D b - a)) $(TROW $(D arr[e-a .. e]), $(D a)) $(TROW $(D arr[e .. e+b]), $(D b)) $(TROW $(D arr[e-a .. e+b]), $(D a + b)) $(TROW $(D arr[e+a .. e+b]), $(D b - a) $(I if) $(D a <= b)) $(TROW $(D arr[e-a .. e-b]), $(D a - b) $(I if) $(D a >= b)) ) ) $(DDOC_BLANKLINE )

$(LNAME2 primary_expressions, Primary Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME PrimaryExpression): $(GLINK_LEX Identifier) $(D .) $(GLINK_LEX Identifier) $(GLINK2 template, TemplateInstance) $(D .) $(GLINK2 template, TemplateInstance) $(RELATIVE_LINK2 this, $(D this)) $(RELATIVE_LINK2 super, $(D super)) $(RELATIVE_LINK2 null, $(D null)) $(LEGACY_LNAME2 true_false)$(DDSUBLINK spec/type, bool, true) $(DDSUBLINK spec/type, bool, false) $(RELATIVE_LINK2 IndexOperation, $) $(GLINK_LEX IntegerLiteral) $(GLINK_LEX FloatLiteral) $(LEGACY_LNAME2 CharacterLiteral)$(LEGACY_LNAME2 character-literal)$(GLINK_LEX CharacterLiteral) $(RELATIVE_LINK2 string_literals, StringLiteral) $(GLINK ArrayLiteral) $(GLINK AssocArrayLiteral) $(GLINK FunctionLiteral) $(GLINK AssertExpression) $(GLINK MixinExpression) $(GLINK ImportExpression) $(GLINK NewExpression) $(GLINK2 type, FundamentalType) $(D .) $(GLINK_LEX Identifier) $(D $(LPAREN)) $(GLINK2 type, Type) $(D $(RPAREN ) .) $(GLINK_LEX Identifier) $(D $(LPAREN)) $(GLINK2 type, Type) $(D $(RPAREN ) .) $(GLINK2 template, TemplateInstance) $(GLINK2 type, FundamentalType) $(D $(LPAREN)) $(GLINK NamedArgumentList)$(OPT ) $(D $(RPAREN )) $(GLINK2 type, TypeCtor) $(D $(LPAREN)) $(GLINK2 type, Type) $(D $(RPAREN )) $(D .) $(GLINK_LEX Identifier) $(GLINK2 type, TypeCtor) $(D $(LPAREN)) $(GLINK2 type, Type) $(D $(RPAREN )) $(D $(LPAREN)) $(GLINK NamedArgumentList)$(OPT ) $(D $(RPAREN )) $(GLINK2 type, Typeof) $(GLINK TypeidExpression) $(GLINK IsExpression) $(D $(LPAREN)) $(GLINK Expression) $(D $(RPAREN )) $(GLINK SpecialKeyword) $(GLINK2 traits, TraitsExpression) ) $(DDOC_BLANKLINE )

$(LNAME2 identifier, .Identifier)

$(DDOC_BLANKLINE ) $(P See $(DDSUBLINK spec/module, module_scope_operators, Module Scope Operator).) $(DDOC_BLANKLINE )

$(LNAME2 this, this)

$(DDOC_BLANKLINE ) $(P Within a constructor or non-static member function, $(D this) resolves to a reference to the object for which the function was called. ) $(P $(DDSUBLINK spec/type, typeof-this, typeof(this)) is valid anywhere inside an aggregate type definition. If a class member function is called with an explicit reference to $(D typeof(this)), a non-virtual call is made:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD class) A { $(D_KEYWORD char) get() { $(D_KEYWORD return) 'A'; } $(D_KEYWORD char) foo() { $(D_KEYWORD return) $(D_KEYWORD typeof)($(D_KEYWORD this)).get(); } $(D_COMMENT // calls `A.get` ) $(D_KEYWORD char) bar() { $(D_KEYWORD return) $(D_KEYWORD this).get(); } $(D_COMMENT // dynamic, same as just `get$(LPAREN)$(RPAREN )` )} $(D_KEYWORD class) B : A { $(D_KEYWORD override) $(D_KEYWORD char) get() { $(D_KEYWORD return) 'B'; } } $(D_KEYWORD void) main() { B b = $(D_KEYWORD new) B(); $(D_KEYWORD assert)(b.foo() == 'A'); $(D_KEYWORD assert)(b.bar() == 'B'); } ) ) $(DDOC_BLANKLINE ) $(P Assignment to $(D this) is not allowed for classes.) $(P See also:) $(UL $(LI $(DDSUBLINK spec/class, delegating-constructors, Delegating Constructors)) $(LI $(DDSUBLINK spec/template, template_this_parameter, template this parameters) ) )

$(LNAME2 super, super)

$(DDOC_BLANKLINE ) $(P $(D super) is identical to $(D this), except that it is cast to $(D this)'s base class. It is an error if there is no base class. (The only extern(D) class without a base class is Object, however, note that extern(C++) classes have no base class unless specified.) If a member function is called with an explicit reference to $(D super), a non-virtual call is made. ) $(DDOC_BLANKLINE ) $(P Assignment to $(D super) is not allowed.) $(P See also: $(DDSUBLINK spec/class, base-construction, Base Class Construction).) $(DDOC_BLANKLINE )

$(LNAME2 null, null)

$(DDOC_BLANKLINE ) $(P $(D null) represents the null value for pointers, pointers to functions, delegates, dynamic arrays, associative arrays, and class objects. If it has not already been cast to a type, it is given the singular type $(D typeof(null)) and it is an exact conversion to convert it to the null value for pointers, pointers to functions, delegates, etc. After it is cast to a type, such conversions are implicit, but no longer exact. ) $(DDOC_BLANKLINE )

$(LEGACY_LNAME2 StringLiteral, string_literals, String Literals)

$(DDOC_BLANKLINE ) $(P See $(GLINK_LEX StringLiteral) grammar.) $(DDOC_BLANKLINE ) $(P String literals are read-only. A string literal without a $(DDSUBLINK spec/lex, string_postfix, StringPostfix) can implicitly convert to any of the following types, which have equal weight: ) $(DDOC_BLANKLINE ) $(TABLE $(TROW $(D immutable(char)*)) $(TROW $(D immutable(wchar)*)) $(TROW $(D immutable(dchar)*)) $(TROW $(D immutable(char)[])) $(TROW $(D immutable(wchar)[])) $(TROW $(D immutable(dchar)[])) ) $(DDOC_BLANKLINE ) $(UNDEFINED_BEHAVIOR writing to a string literal. This is not allowed in @safe code.) $(DDOC_BLANKLINE ) $(P By default, a string literal is typed as a dynamic array, but the element count is known at compile time. So all string literals can be implicitly converted to an immutable static array:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD void) foo($(D_KEYWORD char)[2] a) { $(D_KEYWORD assert)(a[0] == 'b'); } $(D_KEYWORD void) bar($(D_KEYWORD ref) $(D_KEYWORD const) $(D_KEYWORD char)[2] a) { $(D_KEYWORD assert)(a == $(D_STRING "bc")); } $(D_KEYWORD void) main() { foo($(D_STRING "bc")); foo($(D_STRING "b")); $(D_COMMENT // OK ) $(D_COMMENT //foo$(LPAREN)"bcd"$(RPAREN ); // error, too many chars ) bar($(D_STRING "bc")); $(D_COMMENT // OK, same length ) $(D_COMMENT //bar$(LPAREN)"b"$(RPAREN ); // error, lengths must match )} ) ) $(P A string literal converts to a static array rvalue of the same or longer length. Any extra elements are padded with zeros. A string literal can also convert to a static array lvalue of the same length.) $(DDOC_BLANKLINE ) $(P String literals have a '\0' appended to them, which makes them easy to pass to C or C++ functions expecting a null-terminated $(CODE const char*) string. The '\0' is not included in the $(CODE .length) property of the string literal. ) $(DDOC_BLANKLINE ) $(P Concatenation of string literals requires the use of $(RELATIVE_LINK2 cat_expressions, the ~ operator), and is resolved at compile time. C style implicit concatenation without an intervening operator is error prone and not supported in D.) $(DDOC_BLANKLINE )

$(LNAME2 array_literals, Array Literals)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME ArrayLiteral): $(D [) $(I ArrayMemberInitializations)$(OPT ) $(D ]) $(DDOC_BLANKLINE ) $(GNAME ArrayMemberInitializations): $(I ArrayMemberInitialization) $(I ArrayMemberInitialization) $(D ,) $(I ArrayMemberInitialization) $(D ,) $(GSELF ArrayMemberInitializations) $(DDOC_BLANKLINE ) $(GNAME ArrayMemberInitialization): $(GLINK2 declaration, NonVoidInitializer) $(GLINK AssignExpression) $(D :) $(GLINK2 declaration, NonVoidInitializer) ) $(DDOC_BLANKLINE ) $(P An array literal is a comma-separated list of expressions between square brackets $(D [) and $(D ]). The expressions form the elements of a dynamic array. The length of the array is the number of elements. ) $(P The element type of the array is inferred as the common type of all the elements, and each expression is implicitly converted to that type. When there is an expected array type, the elements of the literal will be implicitly converted to the expected element type.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD auto) a1 = [1, 2, 3]; $(D_COMMENT // type is int[], with elements 1, 2 and 3 )$(D_KEYWORD auto) a2 = [1u, 2, 3]; $(D_COMMENT // type is uint[], with elements 1u, 2u, and 3u )$(D_KEYWORD byte)[] a3 = [1, 2, 3]; $(D_COMMENT // OK )$(D_KEYWORD byte)[] a4 = [128]; $(D_COMMENT // error )) $(DDOC_BLANKLINE ) $(PANEL By default, an array literal is typed as a dynamic array, but the element count is known at compile time. Therefore, an array literal can be implicitly converted to a static array of the same length. $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD int)[2] sa = [1, 2]; $(D_COMMENT // OK )$(D_KEYWORD int)[2] sb = [1]; $(D_COMMENT // error )) $(DDOC_BLANKLINE ) $(NOTE Slicing a dynamic array with a statically known slice length also $(RELATIVE_LINK2 slice_to_static_array, allows conversion) to a static array.) ) $(DDOC_BLANKLINE ) $(P If any $(I ArrayMemberInitialization) is a $(DDSUBLINK spec/template, TemplateParameterSequence, ValueSeq), then the elements of the $(I ValueSeq) are inserted as expressions in place of the sequence. ) $(DDOC_BLANKLINE ) $(P Escaping array literals are allocated on the memory managed heap. Thus, they can be returned safely from functions:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD int)[] foo() { $(D_KEYWORD return) [1, 2, 3]; } ) $(DDOC_BLANKLINE ) $(P To initialize an element at a particular index, use the AssignExpression : NonVoidInitializer syntax. The AssignExpression must be known at compile-time. Any missing elements will be initialized to the default value of the element type. Note that if the array type is not specified, the literal will be parsed as an $(RELATIVE_LINK2 associative_array_literals, associative array).) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD int) n = 4; $(D_KEYWORD auto) aa = [0:1, 3:n]; $(D_COMMENT // associative array `int[int]` ) $(D_KEYWORD int)[] a = [1, 3:n, 5]; $(D_KEYWORD assert)(a == [1, 0, 0, n, 5]); $(D_COMMENT //int[] e = [n:2]; // error, n not known at compile-time )) ) $(DDOC_BLANKLINE )

$(LNAME2 cast_array_literal, Casting)

$(DDOC_BLANKLINE ) $(P When array literals are cast to another array type, each element of the array is cast to the new element type. When arrays that are not literals $(RELATIVE_LINK2 cast_array, are cast), the array is reinterpreted as the new type, and the length is recomputed:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_COMMENT // cast array literal )$(D_KEYWORD const) $(D_KEYWORD ubyte)[] ct = $(D_KEYWORD cast)($(D_KEYWORD ubyte)[]) [257, 257]; $(D_COMMENT // this is equivalent to: )$(D_COMMENT // const ubyte[] ct = [cast$(LPAREN)ubyte$(RPAREN ) 257, cast$(LPAREN)ubyte$(RPAREN ) 257]; )writeln(ct); $(D_COMMENT // writes [1, 1] ) $(D_COMMENT // cast other array expression )$(D_COMMENT // --> normal behavior of CastExpression )$(D_KEYWORD byte)[] arr = [1, 1]; $(D_KEYWORD short)[] rt = $(D_KEYWORD cast)($(D_KEYWORD short)[]) arr; writeln(rt); $(D_COMMENT // writes [257] )) ) $(DDOC_BLANKLINE ) In other words, casting an array literal will change the type of each initializer element. $(DDOC_BLANKLINE ) $(BEST_PRACTICE Avoid casting an array literal when the elements could implicitly convert to an expected type. Instead, declare a variable of that type and initialize it with the array literal. Casting is more bug-prone than implicit conversions.) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 associative_array_literals, Associative Array Literals)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME AssocArrayLiteral): $(D [) $(GLINK KeyValuePairs) $(D ]) $(DDOC_BLANKLINE ) $(GNAME KeyValuePairs): $(GLINK KeyValuePair) $(GLINK KeyValuePair) $(D ,) $(GSELF KeyValuePairs) $(DDOC_BLANKLINE ) $(GNAME KeyValuePair): $(GLINK KeyExpression) $(D :) $(GLINK ValueExpression) $(DDOC_BLANKLINE ) $(GNAME KeyExpression): $(GLINK AssignExpression) $(DDOC_BLANKLINE ) $(GNAME ValueExpression): $(GLINK AssignExpression) ) $(DDOC_BLANKLINE ) $(P Associative array literals are a comma-separated list of $(I key)$(D :)$(I value) pairs between square brackets $(D [) and $(D ]). The list cannot be empty. The common type of the all keys is taken to be the key type of the associative array, and all keys are implicitly converted to that type. The common type of the all values is taken to be the value type of the associative array, and all values are implicitly converted to that type. An $(I AssocArrayLiteral) cannot be used to statically initialize anything.) $(DDOC_BLANKLINE ) $(D_CODE [21u: $(D_STRING "he"), 38: $(D_STRING "ho"), 2: $(D_STRING "hi")]; $(D_COMMENT // type is string[uint], ) $(D_COMMENT // with keys 21u, 38u and 2u ) $(D_COMMENT // and values "he", "ho", and "hi" )) $(DDOC_BLANKLINE ) $(P If any of the keys or values in the $(I KeyValuePairs) are a $(I ValueSeq), then the elements of the $(I ValueSeq) are inserted as arguments in place of the sequence. ) $(DDOC_BLANKLINE ) $(P Associative array initializers may contain duplicate keys, however, in that case, the last $(I KeyValuePair) lexicographically encountered is stored. ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD auto) aa = [21: $(D_STRING "he"), 38: $(D_STRING "ho"), 2: $(D_STRING "hi"), 2:$(D_STRING "bye")]; $(D_KEYWORD assert)(aa[2] == $(D_STRING "bye")) ) $(DDOC_BLANKLINE )

$(LNAME2 function_literals, Function Literals)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME FunctionLiteral): $(D function) $(GLINK RefOrAutoRef)$(OPT ) $(GLINK2 type, Type)$(OPT ) $(GLINK ParameterWithAttributes)$(OPT ) $(GLINK FunctionLiteralBody2) $(D delegate) $(GLINK RefOrAutoRef)$(OPT ) $(GLINK2 type, Type)$(OPT ) $(GLINK ParameterWithMemberAttributes)$(OPT ) $(GLINK FunctionLiteralBody2) $(GLINK RefOrAutoRef)$(OPT ) $(GLINK ParameterWithMemberAttributes) $(GLINK FunctionLiteralBody2) $(GLINK2 statement, BlockStatement) $(GLINK_LEX Identifier) $(D =>) $(GLINK AssignExpression) $(DDOC_BLANKLINE ) $(GNAME ParameterWithAttributes): $(GLINK2 function, Parameters) $(GLINK2 function, FunctionAttributes)$(OPT ) $(DDOC_BLANKLINE ) $(GNAME ParameterWithMemberAttributes): $(GLINK2 function, Parameters) $(GLINK2 function, MemberFunctionAttributes)$(OPT ) $(DDOC_BLANKLINE ) $(GNAME FunctionLiteralBody2): $(D =>) $(GLINK AssignExpression) $(GLINK2 function, SpecifiedFunctionBody) $(DDOC_BLANKLINE ) $(GNAME RefOrAutoRef): $(D ref) $(D auto ref) ) $(DDOC_BLANKLINE ) $(P $(I FunctionLiteral)s enable embedding anonymous functions and anonymous delegates directly into expressions. Short function literals are known as $(LNAME2 lambdas, $(I lambdas)). ) $(UL $(LI $(I Type) is the return type of the function or delegate - if omitted it is $(RELATIVE_LINK2 lambda-return-type, inferred).) $(LI $(I ParameterWithAttributes) or $(I ParameterWithMemberAttributes) can be used to specify the parameters for the function. If these are omitted, the function defaults to the empty parameter list $(D ( )).) $(LI Parameter types can be $(RELATIVE_LINK2 lambda-parameter-inference, omitted).) $(LI The type of a function literal is a $(DDSUBLINK spec/function, closures, delegate or a pointer to function). ) ) $(P For example:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD int) $(D_KEYWORD function)($(D_KEYWORD char) c) fp; $(D_COMMENT // declare pointer to a function ) $(D_KEYWORD void) test() { $(D_KEYWORD static) $(D_KEYWORD int) foo($(D_KEYWORD char) c) { $(D_KEYWORD return) 6; } fp = &foo; } ) $(DDOC_BLANKLINE ) is exactly equivalent to: $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD int) $(D_KEYWORD function)($(D_KEYWORD char) c) fp; $(D_KEYWORD void) test() { fp = $(D_KEYWORD function) $(D_KEYWORD int)($(D_KEYWORD char) c) { $(D_KEYWORD return) 6; }; } ) $(DDOC_BLANKLINE ) $(P A delegate is necessary if the $(I FunctionLiteralBody2) accesses any non-static local variables in enclosing functions.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD int) abc($(D_KEYWORD int) $(D_KEYWORD delegate)($(D_KEYWORD int) i)); $(D_KEYWORD void) test() { $(D_KEYWORD int) b = 3; $(D_KEYWORD int) foo($(D_KEYWORD int) c) { $(D_KEYWORD return) 6 + b; } abc(&foo); } ) $(DDOC_BLANKLINE ) is exactly equivalent to: $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD int) abc($(D_KEYWORD int) $(D_KEYWORD delegate)($(D_KEYWORD int) i)); $(D_KEYWORD void) test() { $(D_KEYWORD int) b = 3; abc( $(D_KEYWORD delegate) $(D_KEYWORD int)($(D_KEYWORD int) c) { $(D_KEYWORD return) 6 + b; } ); } ) $(DDOC_BLANKLINE ) $(P The use of ref declares that the return value is returned by reference:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD void) main() { $(D_KEYWORD int) x; $(D_KEYWORD auto) dg = $(D_KEYWORD delegate) $(D_KEYWORD ref) $(D_KEYWORD int)() { $(D_KEYWORD return) x; }; dg() = 3; $(D_KEYWORD assert)(x == 3); } ) ) $(DDOC_BLANKLINE ) $(NOTE When comparing function literals with $(DDSUBLINK spec/function, nested, nested functions), the $(D function) form is analogous to static or non-nested functions, and the $(D delegate) form is analogous to non-static nested functions. I.e. a delegate literal can access non-static local variables in an enclosing function, a function literal cannot. ) $(DDOC_BLANKLINE )

$(LNAME2 lambda-type-inference, Delegate Inference)

$(DDOC_BLANKLINE ) $(P If a literal omits $(D function) or $(D delegate) and there's no expected type from the context, then it is inferred to be a delegate if it accesses a variable in an enclosing function, otherwise it is a function pointer. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD void) test() { $(D_KEYWORD int) b = 3; $(D_KEYWORD auto) fp = ($(D_KEYWORD uint) c) { $(D_KEYWORD return) c * 2; }; $(D_COMMENT // inferred as function pointer ) $(D_KEYWORD auto) dg = ($(D_KEYWORD int) c) { $(D_KEYWORD return) 6 + b; }; $(D_COMMENT // inferred as delegate ) $(D_KEYWORD static) $(D_KEYWORD assert)(!$(D_KEYWORD is)($(D_KEYWORD typeof)(fp) == $(D_KEYWORD delegate))); $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)($(D_KEYWORD typeof)(dg) == $(D_KEYWORD delegate))); } ) ) $(P If a delegate is expected, the literal will be inferred as a delegate even if it accesses no variables from an enclosing function:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD void) abc($(D_KEYWORD int) $(D_KEYWORD delegate)($(D_KEYWORD int) i)) {} $(D_KEYWORD void) def($(D_KEYWORD uint) $(D_KEYWORD function)($(D_KEYWORD uint) s)) {} $(D_KEYWORD void) test() { $(D_KEYWORD int) b = 3; abc( ($(D_KEYWORD int) c) { $(D_KEYWORD return) 6 + b; } ); $(D_COMMENT // inferred as delegate ) abc( ($(D_KEYWORD int) c) { $(D_KEYWORD return) c * 2; } ); $(D_COMMENT // inferred as delegate ) def( ($(D_KEYWORD uint) c) { $(D_KEYWORD return) c * 2; } ); $(D_COMMENT // inferred as function ) $(D_COMMENT //def$(LPAREN) $(LPAREN)uint c$(RPAREN ) { return c * b; } $(RPAREN ); // error! ) $(D_COMMENT // Because the FunctionLiteral accesses b, its type ) $(D_COMMENT // is inferred as delegate. But def cannot accept a delegate argument. )} ) ) $(DDOC_BLANKLINE )

$(LNAME2 lambda-parameter-inference, Parameter Type Inference)

$(DDOC_BLANKLINE ) $(P If the type of a function literal can be uniquely determined from its context, parameter type inference is possible.) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD void) foo($(D_KEYWORD int) $(D_KEYWORD function)($(D_KEYWORD int)) fp); $(D_KEYWORD void) test() { $(D_KEYWORD int) $(D_KEYWORD function)($(D_KEYWORD int)) fp = (n) { $(D_KEYWORD return) n * 2; }; $(D_COMMENT // The type of parameter n is inferred as int. ) foo((n) { $(D_KEYWORD return) n * 2; }); $(D_COMMENT // The type of parameter n is inferred as int. )} ) ) $(D_CODE $(D_KEYWORD auto) fp = (i) { $(D_KEYWORD return) 1; }; $(D_COMMENT // error, cannot infer type of `i` )) $(DDOC_BLANKLINE )

$(LNAME2 function-literal-alias, Function Literal Aliasing)

$(DDOC_BLANKLINE ) $(P Function literals can be $(DDSUBLINK spec/declaration, alias, aliased). Aliasing a function literal with unspecified parameter types produces a $(DDSUBLINK spec/template, function-template, function template) with type parameters for each unspecified parameter type of the literal. Type inference for the literal is then done when the template is instantiated.) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD alias) fpt = (i) { $(D_KEYWORD return) i; }; $(D_COMMENT // ok, infer type of `i` when used )$(D_COMMENT //auto fpt$(LPAREN)T$(RPAREN )$(LPAREN)T i$(RPAREN ) { return i; } // equivalent ) $(D_KEYWORD auto) v = fpt(4); $(D_COMMENT // `i` is inferred as int )$(D_KEYWORD auto) d = fpt(10.3); $(D_COMMENT // `i` is inferred as double ) $(D_KEYWORD alias) fp = fpt!$(D_KEYWORD float); $(D_KEYWORD auto) f = fp(0); $(D_COMMENT // f is a float )) ) $(DDOC_BLANKLINE )

$(LNAME2 lambda-return-type, Return Type Inference)

$(DDOC_BLANKLINE ) $(P The return type of the $(GLINK FunctionLiteral) can be inferred from either the AssignExpression, or any $(GLINK2 statement, ReturnStatement)s in the $(I BlockStatement). If there is a different expected type from the context, and the initial inferred return type implicitly converts to the expected type, then the return type is inferred as the expected type.) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD auto) fi = ($(D_KEYWORD int) i) { $(D_KEYWORD return) i; }; $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)($(D_KEYWORD typeof)(fi(5)) == $(D_KEYWORD int))); $(D_KEYWORD long) $(D_KEYWORD function)($(D_KEYWORD int)) fl = ($(D_KEYWORD int) i) { $(D_KEYWORD return) i; }; $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)($(D_KEYWORD typeof)(fl(5)) == $(D_KEYWORD long))); ) ) $(DDOC_BLANKLINE )

$(LNAME2 lambda-short-syntax, Nullary Short Syntax)

$(DDOC_BLANKLINE ) $(P Parameters can be omitted completely for a function literal when there is a BlockStatement function body.) $(DDOC_BLANKLINE ) $(NOTE This form is not allowed to be immediately called as an ExpressionStatement, because it would require arbitrary lookahead to distinguish it from a BlockStatement.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD auto) f = { writeln($(D_STRING "hi")); }; $(D_COMMENT // OK, f has type `void function$(LPAREN)$(RPAREN )` )f(); { writeln($(D_STRING "hi")); }(); $(D_COMMENT // error )() { writeln($(D_STRING "hi")); }(); $(D_COMMENT // OK )) $(DDOC_BLANKLINE ) $(PANEL Anonymous delegates can behave like arbitrary statement literals. For example, here an arbitrary statement is executed by a loop: $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD void) loop($(D_KEYWORD int) n, $(D_KEYWORD void) $(D_KEYWORD delegate)() statement) { $(D_KEYWORD foreach) (_; 0 .. n) { statement(); } } $(D_KEYWORD void) main() { $(D_KEYWORD int) n = 0; loop(5, { n += 1; }); $(D_KEYWORD assert)(n == 5); } ) ) ) $(DDOC_BLANKLINE )

$(LNAME2 lambda-short-body, Shortened Body Syntax)

$(DDOC_BLANKLINE ) $(P The syntax $(D => AssignExpression) is equivalent to $(D { return AssignExpression; }).) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD void) main() { $(D_KEYWORD auto) i = 3; $(D_KEYWORD auto) twice = $(D_KEYWORD function) ($(D_KEYWORD int) x) => x * 2; $(D_KEYWORD assert)(twice(i) == 6); $(D_KEYWORD auto) square = $(D_KEYWORD delegate) () => i * i; $(D_KEYWORD assert)(square() == 9); $(D_KEYWORD auto) n = 5; $(D_KEYWORD auto) mul_n = ($(D_KEYWORD int) x) => x * n; $(D_KEYWORD assert)(mul_n(i) == 15); } ) ) $(DDOC_BLANKLINE ) $(P The syntax $(D Identifier => AssignExpression) is equivalent to $(D (Identifier) { return AssignExpression; }).) $(DDOC_BLANKLINE ) $(D_CODE $(D_COMMENT // the following two declarations are equivalent )$(D_KEYWORD alias) fp = i => 1; $(D_KEYWORD alias) fp = (i) { $(D_KEYWORD return) 1; }; ) $(DDOC_BLANKLINE ) $(BEST_PRACTICE The minimal form of the function literal is most useful as an argument to a template alias parameter: $(D_CODE $(D_KEYWORD int) motor($(D_KEYWORD alias) fp)($(D_KEYWORD int) i) { $(D_KEYWORD return) fp(i) + 1; } $(D_KEYWORD int) engine() { $(D_KEYWORD return) motor!(i => i * 2)(6); $(D_COMMENT // returns 13 )} ) ) $(DDOC_BLANKLINE ) $(NOTE The syntax Identifier { statement; } is not supported because it is easily confused with statements x = Identifier; { statement; }; if the semicolons were accidentally omitted. ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 uniform_construction_syntax, Uniform construction syntax for built-in scalar types)

$(DDOC_BLANKLINE ) $(P The implicit conversions of built-in scalar types can be explicitly represented by using function call syntax. For example:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD auto) a = $(D_KEYWORD short)(1); $(D_COMMENT // implicitly convert an integer literal '1' to short )$(D_KEYWORD auto) b = $(D_KEYWORD double)(a); $(D_COMMENT // implicitly convert a short variable 'a' to double )$(D_KEYWORD auto) c = $(D_KEYWORD byte)(128); $(D_COMMENT // error, 128 cannot be represented in a byte )) $(DDOC_BLANKLINE ) $(P If the argument is omitted, it means default construction of the scalar type:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD auto) a = $(D_KEYWORD ushort)(); $(D_COMMENT // same as: ushort.init )$(D_KEYWORD auto) b = $(D_KEYWORD wchar)(); $(D_COMMENT // same as: wchar.init )) $(DDOC_BLANKLINE ) $(P See also: $(DDSUBLINK spec/type, usual-arithmetic-conversions, Usual Arithmetic Conversions).) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 assert_expressions, Assert Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME AssertExpression): $(D assert $(LPAREN)) $(GLINK AssertArguments) $(D $(RPAREN )) $(DDOC_BLANKLINE ) $(GNAME AssertArguments): $(GLINK AssignExpression) $(D ,)$(OPT ) $(GLINK AssignExpression) $(D ,) $(GLINK AssignExpression) $(D ,)$(OPT ) ) $(DDOC_BLANKLINE ) $(P The first $(I AssignExpression) is evaluated and converted to a boolean value. If the value is not true, an $(I Assert Failure) has occurred and the program enters an $(I Invalid State). ) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD int) i = fun(); $(D_KEYWORD assert)(i > 0); ) $(DDOC_BLANKLINE ) $(P $(I AssertExpression) has different semantics if it is in a $(DDLINK spec/unittest, Unit Tests, $(D unittest)) or $(DDSUBLINK spec/function, preconditions, $(D in) contract). ) $(DDOC_BLANKLINE ) $(P If the first $(I AssignExpression) is a reference to a class instance for which a $(DDSUBLINK spec/class, invariants, class Invariant) exists, the class $(I Invariant) must hold. ) $(DDOC_BLANKLINE ) $(P If the first $(I AssignExpression) is a pointer to a struct instance for which a $(DDSUBLINK spec/struct, Invariant, struct $(I Invariant)) exists, the struct $(I Invariant) must hold. ) $(DDOC_BLANKLINE ) $(P The type of an $(I AssertExpression) is $(D void). ) $(DDOC_BLANKLINE ) $(UNDEFINED_BEHAVIOR Once in an $(I Invalid State) the behavior of the continuing execution of the program is undefined.) $(DDOC_BLANKLINE ) $(PANEL $(IMPLEMENTATION_DEFINED Whether the first $(I AssertExpression) is evaluated or not (at runtime) is typically set with a compiler switch. If it is not evaluated, any side effects specified by the $(I AssertExpression) may not occur. The behavior when the first $(I AssertExpression) evaluates to false is also typically set with a compiler switch, and may include these options: $(OL $(LI Immediately halting via execution of a special CPU instruction) $(LI Aborting the program) $(LI Calling the assert failure function in the corresponding C runtime library) $(LI Throwing the $(D AssertError) exception in the D runtime library) ) ) $(DDOC_BLANKLINE ) $(NOTE Throwing $(D AssertError) is the default for $(B dmd), with an optional $(DDSUBLINK dmd, switch-checkaction, $(B -checkaction=context)) switch to show certain sub-expressions used in the first AssertExpression in the error message:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD auto) x = 4; $(D_KEYWORD assert)(x < 3); ) When in use, the above will throw an AssertError with a message 4 >= 3. ) $(DDOC_BLANKLINE ) $(BEST_PRACTICE $(OL $(LI Do not have side effects in either $(I AssignExpression) that subsequent code depends on.) $(LI $(I AssertExpression)s are intended to detect bugs in the program. Do not use them for detecting input or environmental errors.) $(LI Do not attempt to resume normal execution after an $(I Assert Failure).) ) ) $(DDOC_BLANKLINE )

$(LNAME2 assert-ct, Compile-time Evaluation)

$(DDOC_BLANKLINE ) $(P If the first $(I AssignExpression) consists entirely of compile time constants, and evaluates to false, it is a special case - it signifies that subsequent statements are unreachable code. Compile Time Function Execution (CTFE) is not attempted. ) $(DDOC_BLANKLINE ) $(P The implementation may handle the case of the first $(I AssignExpression) evaluating to false at compile time differently - even when other asserts are ignored, it may still generate a $(D HLT) instruction or equivalent. ) $(DDOC_BLANKLINE ) $(P See also: $(DDSUBLINK spec/version, static-assert, static assert).) $(DDOC_BLANKLINE )

$(LNAME2 assert-message, Assert Message)

$(DDOC_BLANKLINE ) $(P The second $(I AssignExpression), if present, must be implicitly convertible to type $(D const(char)[]). When present, the implementation may evaluate it and print the resulting message upon assert failure: ) $(D_CODE $(D_KEYWORD void) main() { $(D_KEYWORD assert)(0, $(D_STRING "an") ~ $(D_STRING " error message")); } ) $(DDOC_BLANKLINE ) $(P When compiled and run, it will produce the message:) $(DDOC_BLANKLINE ) $(CONSOLE core.exception.AssertError@test.d(3) an error message) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 mixin_expressions, Mixin Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME MixinExpression): $(D mixin $(LPAREN)) $(GLINK ArgumentList) $(D $(RPAREN )) ) $(DDOC_BLANKLINE ) $(P Each $(GLINK AssignExpression) in the $(I ArgumentList) is evaluated at compile time, and the result must be representable as a string. The resulting strings are concatenated to form a string. The text contents of the string must be compilable as a valid $(GLINK Expression), and is compiled as such.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD int) foo($(D_KEYWORD int) x) { $(D_KEYWORD return) $(D_KEYWORD mixin)($(D_STRING "x +"), 1) * 7; $(D_COMMENT // same as $(LPAREN)$(LPAREN)x + 1$(RPAREN ) * 7$(RPAREN ) )} ) $(DDOC_BLANKLINE )

$(LNAME2 import_expressions, Import Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME ImportExpression): $(D import $(LPAREN)) $(GLINK AssignExpression) $(D $(RPAREN )) ) $(DDOC_BLANKLINE ) $(P The $(I AssignExpression) must evaluate at compile time to a constant string. The text contents of the string are interpreted as a file name. The file is read, and the exact contents of the file become a string literal. ) $(DDOC_BLANKLINE ) $(P Implementations may restrict the file name in order to avoid directory traversal security vulnerabilities. A possible restriction might be to disallow any path components in the file name. ) $(DDOC_BLANKLINE ) $(P Note that by default an import expression will not compile unless one or more paths are passed via the $(B -J) switch. This tells the compiler where it should look for the files to import. This is a security feature.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD void) foo() { $(D_COMMENT // Prints contents of file foo.txt ) writeln($(D_KEYWORD import)($(D_STRING "foo.txt"))); } ) $(DDOC_BLANKLINE )

$(LNAME2 new_expressions, New Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME NewExpression): $(D new) $(GLINK2 type, Type) $(D new) $(GLINK2 type, Type) $(D [) $(GLINK AssignExpression) $(D ]) $(D new) $(GLINK2 type, Type) $(D $(LPAREN)) $(GLINK NamedArgumentList)$(OPT ) $(D $(RPAREN )) $(GLINK2 class, NewAnonClassExpression) ) $(DDOC_BLANKLINE ) $(P $(I NewExpression)s allocate memory on the $(DDLINK spec/garbage, Garbage Collection, garbage collected) heap by default. ) $(DDOC_BLANKLINE ) $(P The new Type form constructs an instance of a type and default-initializes it.) $(P The Type(NamedArgumentList) form allows passing either a single initializer of the same type, or multiple arguments for more complex types. For class types, NamedArgumentList is passed to the class constructor. For a dynamic array, the argument sets the initial array length. For multidimensional dynamic arrays, each argument corresponds to an initial length (see $(RELATIVE_LINK2 new_multidimensional, below)).) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD int)* i = $(D_KEYWORD new) $(D_KEYWORD int); $(D_KEYWORD assert)(*i == 0); i = $(D_KEYWORD new) $(D_KEYWORD int)(5); $(D_KEYWORD assert)(*i == 5); Object o = $(D_KEYWORD new) Object; Exception e = $(D_KEYWORD new) Exception($(D_STRING "info")); $(D_KEYWORD auto) a = $(D_KEYWORD new) $(D_KEYWORD int)[](2); $(D_KEYWORD assert)(a.length == 2); ) ) $(DDOC_BLANKLINE ) $(P The Type[AssignExpression] form allocates a dynamic array with length equal to AssignExpression. It is preferred to use the Type(NamedArgumentList) form when allocating dynamic arrays instead, as it is more general.) $(DDOC_BLANKLINE ) $(NOTE It is not possible to allocate a static array directly with new (only by using a type alias).) $(DDOC_BLANKLINE ) $(P The result is a $(DDSUBLINK const3, unique-expressions, unique expression) which can implicitly convert to other qualifiers:) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD immutable) o = $(D_KEYWORD new) Object; ) $(DDOC_BLANKLINE )

$(LNAME2 new_class, Class Instantiation)

$(DDOC_BLANKLINE ) $(P If a $(I NewExpression) is used with a class type as an initializer for a function local variable with $(DDSUBLINK spec/attribute, scope, scope) storage class, then the instance is $(DDSUBLINK spec/attribute, scope-class-var, allocated on the stack). ) $(DDOC_BLANKLINE ) $(P new can also be used to allocate a $(DDSUBLINK spec/class, nested-explicit, nested class).) $(DDOC_BLANKLINE )

$(LNAME2 new_multidimensional, Multidimensional Arrays)

$(DDOC_BLANKLINE ) $(P To allocate multidimensional arrays, the declaration reads in the same order as the prefix array declaration order.) $(DDOC_BLANKLINE ) $(D_CODE $(D_KEYWORD char)[][] foo; $(D_COMMENT // dynamic array of strings )... foo = $(D_KEYWORD new) $(D_KEYWORD char)[][30]; $(D_COMMENT // allocate array of 30 strings )) $(DDOC_BLANKLINE ) $(P The above allocation can also be written as:) $(DDOC_BLANKLINE ) $(D_CODE foo = $(D_KEYWORD new) $(D_KEYWORD char)[][](30); $(D_COMMENT // allocate array of 30 strings )) $(DDOC_BLANKLINE ) $(P To allocate the nested arrays, multiple arguments can be used:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_RUN $(D_CODE $(D_KEYWORD int)[][][] bar; bar = $(D_KEYWORD new) $(D_KEYWORD int)[][][](5, 20, 30); $(D_KEYWORD assert)(bar.length == 5); $(D_KEYWORD assert)(bar[0].length == 20); $(D_KEYWORD assert)(bar[0][0].length == 30); ) ) $(DDOC_BLANKLINE ) The assignment above is equivalent to: $(DDOC_BLANKLINE ) $(D_CODE bar = $(D_KEYWORD new) $(D_KEYWORD int)[][][5]; $(D_KEYWORD foreach) ($(D_KEYWORD ref) a; bar) { a = $(D_KEYWORD new) $(D_KEYWORD int)[][20]; $(D_KEYWORD foreach) ($(D_KEYWORD ref) b; a) { b = $(D_KEYWORD new) $(D_KEYWORD int)[30]; } } ) $(DDOC_BLANKLINE )

$(LNAME2 typeid_expressions, Typeid Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME TypeidExpression): $(D typeid $(LPAREN)) $(GLINK2 type, Type) $(D $(RPAREN )) $(D typeid $(LPAREN)) $(GLINK Expression) $(D $(RPAREN )) ) $(DDOC_BLANKLINE ) $(P If $(I Type), returns an instance of class $(DPLLINK phobos/object.html, $(D TypeInfo)) corresponding to $(I Type). ) $(DDOC_BLANKLINE ) $(P If $(I Expression), returns an instance of class $(DPLLINK phobos/object.html, $(D TypeInfo)) corresponding to the type of the $(I Expression). If the type is a class, it returns the $(D TypeInfo) of the dynamic type (i.e. the most derived type). The $(I Expression) is always executed.) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD class) A { } $(D_KEYWORD class) B : A { } $(D_KEYWORD void) main() { $(D_KEYWORD import) std.stdio; writeln($(D_KEYWORD typeid)($(D_KEYWORD int))); $(D_COMMENT // int ) $(D_KEYWORD uint) i; writeln($(D_KEYWORD typeid)(i++)); $(D_COMMENT // uint ) writeln(i); $(D_COMMENT // 1 ) A a = $(D_KEYWORD new) B(); writeln($(D_KEYWORD typeid)(a)); $(D_COMMENT // B ) writeln($(D_KEYWORD typeid)($(D_KEYWORD typeof)(a))); $(D_COMMENT // A )} ) ) $(DDOC_BLANKLINE )

$(LNAME2 is_expression, Is Expressions)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME IsExpression): $(D is $(LPAREN)) $(GLINK2 type, Type) $(D $(RPAREN )) $(D is $(LPAREN)) $(GLINK2 type, Type) $(D :) $(GLINK TypeSpecialization) $(D $(RPAREN )) $(D is $(LPAREN)) $(GLINK2 type, Type) $(D ==) $(GLINK TypeSpecialization) $(D $(RPAREN )) $(D is $(LPAREN)) $(GLINK2 type, Type) $(D :) $(GLINK TypeSpecialization) $(D ,) $(GLINK2 template, TemplateParameterList) $(D $(RPAREN )) $(D is $(LPAREN)) $(GLINK2 type, Type) $(D ==) $(GLINK TypeSpecialization) $(D ,) $(GLINK2 template, TemplateParameterList) $(D $(RPAREN )) $(D is $(LPAREN)) $(GLINK2 type, Type) $(GLINK_LEX Identifier) $(D $(RPAREN )) $(D is $(LPAREN)) $(GLINK2 type, Type) $(GLINK_LEX Identifier) $(D :) $(GLINK TypeSpecialization) $(D $(RPAREN )) $(D is $(LPAREN)) $(GLINK2 type, Type) $(GLINK_LEX Identifier) $(D ==) $(GLINK TypeSpecialization) $(D $(RPAREN )) $(D is $(LPAREN)) $(GLINK2 type, Type) $(GLINK_LEX Identifier) $(D :) $(GLINK TypeSpecialization) $(D ,) $(GLINK2 template, TemplateParameterList) $(D $(RPAREN )) $(D is $(LPAREN)) $(GLINK2 type, Type) $(GLINK_LEX Identifier) $(D ==) $(GLINK TypeSpecialization) $(D ,) $(GLINK2 template, TemplateParameterList) $(D $(RPAREN )) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE ) $(GNAME TypeSpecialization): $(GLINK2 type, Type) $(GLINK2 type, TypeCtor) $(D struct) $(D union) $(D class) $(D interface) $(D enum) $(D __vector) $(D function) $(D delegate) $(D super) $(D return) $(D __parameters) $(D module) $(D package) ) $(DDOC_BLANKLINE ) $(P An $(I IsExpression) is evaluated at compile time and is used to check if an expression is a valid type. In addition, there are forms which can also:) $(UL $(LI compare types for equivalence) $(LI determine if one type can be implicitly converted to another) $(LI deduce the subtypes of a type using $(RELATIVE_LINK2 is-parameter-list, pattern matching)) $(LI deduce the template arguments of a type template instance) ) $(P The result of an $(I IsExpression) is a boolean which is true if the condition is satisfied and false if not. ) $(DDOC_BLANKLINE ) $(P $(I Type) is the type being tested. It must be syntactically correct, but it need not be semantically correct. If it is not semantically correct, the condition is not satisfied. ) $(DDOC_BLANKLINE ) $(P $(I TypeSpecialization) is the type that $(I Type) is being pattern matched against. ) $(DDOC_BLANKLINE ) $(P $(I IsExpression)s may be used in conjunction with $(DDSUBLINK spec/type, typeof, typeof) to check whether an expression type checks correctly. For example, $(D is(typeof(foo))) will return $(D true) if $(D foo) has a valid type. ) $(DDOC_BLANKLINE )

$(LNAME2 basic-forms, Basic Forms)

$(DDOC_BLANKLINE )
$(LNAME2 is-type, $(D is $(LPAREN)) $(I Type) $(D $(RPAREN )))
$(DDOC_BLANKLINE ) $(P The condition is satisfied if $(I Type) is semantically correct. Type must be syntactically correct regardless. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_FAIL $(D_CODE $(D_KEYWORD pragma)(msg, $(D_KEYWORD is)(5)); $(D_COMMENT // error )$(D_KEYWORD pragma)(msg, $(D_KEYWORD is)([][])); $(D_COMMENT // error )) ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD int) i; $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)($(D_KEYWORD int))); $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)($(D_KEYWORD typeof)(i))); $(D_COMMENT // same ) $(D_KEYWORD static) $(D_KEYWORD assert)(!$(D_KEYWORD is)(Undefined)); $(D_KEYWORD static) $(D_KEYWORD assert)(!$(D_KEYWORD is)($(D_KEYWORD typeof)($(D_KEYWORD int)))); $(D_COMMENT // int is not an expression )$(D_KEYWORD static) $(D_KEYWORD assert)(!$(D_KEYWORD is)(i)); $(D_COMMENT // i is a value ) $(D_KEYWORD alias) Func = $(D_KEYWORD int)($(D_KEYWORD int)); $(D_COMMENT // function type )$(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)(Func)); $(D_KEYWORD static) $(D_KEYWORD assert)(!$(D_KEYWORD is)(Func[])); $(D_COMMENT // fails as an array of functions is not allowed )) )
$(LNAME2 is-type-convert, $(D is $(LPAREN)) $(I Type) $(D :) $(I TypeSpecialization) $(D $(RPAREN )))
$(DDOC_BLANKLINE ) $(P The condition is satisfied if $(I Type) is semantically correct and it is the same as or can be implicitly converted to $(I TypeSpecialization). $(I TypeSpecialization) is only allowed to be a $(I Type). ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD alias) Bar = $(D_KEYWORD short); $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)(Bar : $(D_KEYWORD int))); $(D_COMMENT // short implicitly converts to int )$(D_KEYWORD static) $(D_KEYWORD assert)(!$(D_KEYWORD is)(Bar : string)); ) )
$(LNAME2 is-type-equal, $(D is $(LPAREN)) $(I Type) $(D ==) $(I TypeSpecialization) $(D $(RPAREN )))
$(DDOC_BLANKLINE ) $(P If TypeSpecialization is a type, the condition is satisfied if $(I Type) is semantically correct and is the same type as $(I TypeSpecialization). ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD alias) Bar = $(D_KEYWORD short); $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)(Bar == $(D_KEYWORD short))); $(D_KEYWORD static) $(D_KEYWORD assert)(!$(D_KEYWORD is)(Bar == $(D_KEYWORD int))); ) ) $(P If TypeSpecialization is a $(GLINK2 type, TypeCtor) then the condition is satisfied if Type is of that TypeCtor: ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)($(D_KEYWORD const) $(D_KEYWORD int) == $(D_KEYWORD const))); $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)($(D_KEYWORD const) $(D_KEYWORD int)[] == $(D_KEYWORD const))); $(D_KEYWORD static) $(D_KEYWORD assert)(!$(D_KEYWORD is)($(D_KEYWORD const)($(D_KEYWORD int))[] == $(D_KEYWORD const))); $(D_COMMENT // head is mutable )$(D_KEYWORD static) $(D_KEYWORD assert)(!$(D_KEYWORD is)($(D_KEYWORD immutable) $(D_KEYWORD int) == $(D_KEYWORD const))); ) ) $(P If $(I TypeSpecialization) is one of $(D struct) $(D union) $(D class) $(D interface) $(D enum) $(D __vector) $(D function) $(D delegate) $(D module) $(D package) then the condition is satisfied if $(I Type) is one of those. ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)(Object == $(D_KEYWORD class))); $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)(ModuleInfo == $(D_KEYWORD struct))); $(D_KEYWORD static) $(D_KEYWORD assert)(!$(D_KEYWORD is)($(D_KEYWORD int) == $(D_KEYWORD class))); ) ) $(P The module and package forms are satisfied when Type is a symbol, not a type, unlike the other forms. The $(DDSUBLINK spec/traits, isModule, isModule) and $(DDSUBLINK spec/traits, isPackage, isPackage) __traits should be used instead. $(DDSUBLINK spec/module, package-module, Package modules) are considered to be both packages and modules. ) $(P TypeSpecialization can also be one of these keywords: ) $(TABLE keyword, condition $(TROW super, true if Type is a class or interface) $(TROW return, $(ARGS true if Type is a function, delegate or function pointer)) $(TROW __parameters, $(ARGS true if Type is a function, delegate or function pointer)) ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD class) C {} $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)(C == $(D_KEYWORD super))); $(D_KEYWORD void) foo($(D_KEYWORD int) i); $(D_KEYWORD static) $(D_KEYWORD assert)(!$(D_KEYWORD is)(foo == $(D_KEYWORD return))); $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)($(D_KEYWORD typeof)(foo) == $(D_KEYWORD return))); $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)($(D_KEYWORD typeof)(foo) == $(D_KEYWORD __parameters))); ) ) $(P $(B See also:) $(DDLINK spec/traits, Traits, Traits).) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 is-identifier, Identifier Forms)

$(DDOC_BLANKLINE ) $(P Identifier is declared to be an alias of the resulting type if the condition is satisfied. The Identifier forms can only be used if the $(I IsExpression) appears in a $(GLINK2 version, StaticIfCondition) or the first argument of a $(GLINK2 version, StaticAssert). ) $(DDOC_BLANKLINE )
$(LNAME2 is-type-identifier, $(D is $(LPAREN)) $(I Type) $(I Identifier) $(D $(RPAREN )))
$(DDOC_BLANKLINE ) $(P The condition is satisfied if $(I Type) is semantically correct. If so, $(I Identifier) is declared to be an alias of $(I Type). ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD struct) S { $(D_KEYWORD int) i, j; } $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)($(D_KEYWORD typeof)(S.i) T) && T.sizeof == 4); ) ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD alias) Bar = $(D_KEYWORD short); $(D_KEYWORD void) foo() { $(D_KEYWORD static) $(D_KEYWORD if) ($(D_KEYWORD is)(Bar T)) $(D_KEYWORD alias) S = T; $(D_KEYWORD else) $(D_KEYWORD alias) S = $(D_KEYWORD long); $(D_KEYWORD pragma)(msg, S); $(D_COMMENT // short ) $(D_COMMENT // if T was defined, it remains in scope ) $(D_KEYWORD if) ($(D_KEYWORD is)(T)) $(D_KEYWORD pragma)(msg, T); $(D_COMMENT // short ) $(D_COMMENT //if $(LPAREN)is$(LPAREN)Bar U$(RPAREN )$(RPAREN ) {} // error, cannot declare U here )} ) ) $(DDOC_BLANKLINE )
$(LNAME2 is-identifier-convert, $(D is $(LPAREN)) $(I Type) $(I Identifier) $(D :) $(I TypeSpecialization) $(D $(RPAREN )) ) $(DDOC_BLANKLINE ) $(P If TypeSpecialization is a type, the condition is satisfied if $(I Type) is semantically correct and it is the same as or can be implicitly converted to $(I TypeSpecialization). $(I Identifier) is declared to be an alias of the $(I TypeSpecialization). ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD alias) Bar = $(D_KEYWORD int); $(D_KEYWORD static) $(D_KEYWORD if) ($(D_KEYWORD is)(Bar T : $(D_KEYWORD int))) $(D_KEYWORD alias) S = T; $(D_KEYWORD else) $(D_KEYWORD alias) S = $(D_KEYWORD long); $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)(S == $(D_KEYWORD int))); ) ) $(P If $(I TypeSpecialization) is a type pattern involving $(I Identifier), type deduction of $(I Identifier) is attempted based on either Type or a type that it implicitly converts to. The condition is only satisfied if the type pattern is matched. ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD struct) S { $(D_KEYWORD long)* i; $(D_KEYWORD alias) i $(D_KEYWORD this); $(D_COMMENT // S converts to long* )} $(D_KEYWORD static) $(D_KEYWORD if) ($(D_KEYWORD is)(S U : U*)) $(D_COMMENT // S is matched against the pattern U* ){ U u; } $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)(U == $(D_KEYWORD long))); ) ) $(DDOC_BLANKLINE ) $(P The way the type of $(I Identifier) is determined is analogous to the way template parameter types are determined by $(GLINK2 template, TemplateTypeParameterSpecialization). ) $(DDOC_BLANKLINE )
$(LNAME2 is-identifier-equal, $(D is $(LPAREN)) $(I Type) $(I Identifier) $(D ==) $(I TypeSpecialization) $(D $(RPAREN )))
$(DDOC_BLANKLINE ) $(P If TypeSpecialization is a type, the condition is satisfied if $(I Type) is semantically correct and is the same type as $(I TypeSpecialization). $(I Identifier) is declared to be an alias of the $(I TypeSpecialization). ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD const) x = 5; $(D_KEYWORD static) $(D_KEYWORD if) ($(D_KEYWORD is)($(D_KEYWORD typeof)(x) T == $(D_KEYWORD const) $(D_KEYWORD int))) $(D_COMMENT // satisfied, T is now defined ) $(D_KEYWORD alias) S = T; $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)(T)); $(D_COMMENT // T is in scope )$(D_KEYWORD pragma)(msg, T); $(D_COMMENT // const int )) ) $(DDOC_BLANKLINE ) $(P If $(I TypeSpecialization) is a type pattern involving $(I Identifier), type deduction of $(I Identifier) is attempted based on Type. The condition is only satisfied if the type pattern is matched. ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD alias) Foo = $(D_KEYWORD long)*; $(D_KEYWORD static) $(D_KEYWORD if) ($(D_KEYWORD is)(Foo U == U*)) $(D_COMMENT // Foo is matched against the pattern U* ){ U u; } $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)(U == $(D_KEYWORD long))); ) ) $(P If TypeSpecialization is a valid keyword for the $(RELATIVE_LINK2 is-type-equal, is(Type == Keyword) form), the condition is satisfied in the same manner. $(I Identifier) is set as follows: ) $(DDOC_BLANKLINE ) $(TABLE_2COLS , keyword, alias type for $(I Identifier) $(DDOC_BLANKLINE ) $(TROW $(CODE struct), $(I Type)) $(TROW $(D union), $(I Type)) $(TROW $(D class), $(I Type)) $(TROW $(D interface), $(I Type)) $(TROW $(D super), $(I TypeSeq) of base classes and interfaces) $(TROW $(D enum), the base type of the enum) $(TROW $(D __vector), the static array type of the vector) $(TROW $(D function), $(ARGS $(I TypeSeq) of the function parameter types. For C- and D-style variadic functions, only the non-variadic parameters are included. For typesafe variadic functions, the $(D ...) is ignored.)) $(TROW $(CODE delegate), the function type of the delegate) $(TROW $(CODE return), $(ARGS the return type of the function, delegate, or function pointer)) $(TROW $(CODE __parameters), $(ARGS the parameter sequence of a function, delegate, or function pointer. This includes the parameter types, names, and default values.)) $(TROW $(D const), $(I Type)) $(TROW $(D immutable), $(I Type)) $(TROW $(D inout), $(I Type)) $(TROW $(D shared), $(I Type)) $(TROW $(D module), the module) $(TROW $(D package), the package) ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD enum) E : $(D_KEYWORD byte) { Emember } $(D_KEYWORD static) $(D_KEYWORD if) ($(D_KEYWORD is)(E V == $(D_KEYWORD enum))) $(D_COMMENT // satisfied, E is an enum ) V v; $(D_COMMENT // v is declared to be a byte ) $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)(V == $(D_KEYWORD byte))); ) ) $(DDOC_BLANKLINE )

$(LNAME2 is-parameter-list, Parameter List Forms)

$(DDOC_BLANKLINE ) $(GRAMMAR_INFORMATIVE $(D is $(LPAREN)) $(I Type) $(D :) $(I TypeSpecialization) $(D ,) $(GLINK2 template, TemplateParameterList) $(D $(RPAREN )) $(D is $(LPAREN)) $(I Type) $(D ==) $(I TypeSpecialization) $(D ,) $(GLINK2 template, TemplateParameterList) $(D $(RPAREN )) $(D is $(LPAREN)) $(I Type) $(I Identifier) $(D :) $(I TypeSpecialization) $(D ,) $(GLINK2 template, TemplateParameterList) $(D $(RPAREN )) $(D is $(LPAREN)) $(I Type) $(I Identifier) $(D ==) $(I TypeSpecialization) $(D ,) $(GLINK2 template, TemplateParameterList) $(D $(RPAREN )) ) $(DDOC_BLANKLINE ) $(P More complex types can be pattern matched. The $(I TemplateParameterList) declares symbols based on the parts of the pattern that are matched, analogously to the way $(DDSUBLINK spec/template, parameters_specialization, implied template parameters) are matched. ) $(DDOC_BLANKLINE ) $(P $(B Example:) Matching a Template Instantiation) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD struct) Tuple(T...) { $(D_COMMENT // ... )} $(D_KEYWORD alias) Tup2 = Tuple!($(D_KEYWORD int), string); $(D_KEYWORD static) $(D_KEYWORD if) ($(D_KEYWORD is)(Tup2 : Template!Args, $(D_KEYWORD alias) Template, Args...)) { $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD __traits)(isSame, Template, Tuple)); $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)(Template!($(D_KEYWORD int), string) == Tup2)); $(D_COMMENT // same struct )} $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)(Args[0] == $(D_KEYWORD int))); $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)(Args[1] == string)); ) ) $(DDOC_BLANKLINE ) $(P Type cannot be matched when TypeSpecialization is an $(DDSUBLINK spec/template, alias-template, alias template) instance: ) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD struct) S(T) {} $(D_KEYWORD alias) A(T) = S!T; $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)(A!$(D_KEYWORD int) : S!T, T)); $(D_COMMENT //static assert$(LPAREN)!is$(LPAREN)A!int : A!T, T$(RPAREN )$(RPAREN ); )) ) $(DDOC_BLANKLINE ) $(P $(B Example:) Matching an Associative Array) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD alias) AA = $(D_KEYWORD long)[string]; $(D_KEYWORD static) $(D_KEYWORD if) ($(D_KEYWORD is)(AA T : T[U], U : string)) $(D_COMMENT // T[U] is the pattern ){ $(D_KEYWORD pragma)(msg, T); $(D_COMMENT // long ) $(D_KEYWORD pragma)(msg, U); $(D_COMMENT // string )} $(D_COMMENT // no match, B is not an int )$(D_KEYWORD static) $(D_KEYWORD assert)(!$(D_KEYWORD is)(AA A : A[B], B : $(D_KEYWORD int))); ) ) $(DDOC_BLANKLINE ) $(P $(B Example:) Matching a Static Array) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD static) $(D_KEYWORD if) ($(D_KEYWORD is)($(D_KEYWORD int)[10] W : W[len], $(D_KEYWORD int) len)) $(D_COMMENT // W[len] is the pattern ){ $(D_KEYWORD static) $(D_KEYWORD assert)(len == 10); } $(D_KEYWORD static) $(D_KEYWORD assert)($(D_KEYWORD is)(W == $(D_KEYWORD int))); $(D_COMMENT // no match, len should be 10 )$(D_KEYWORD static) $(D_KEYWORD assert)(!$(D_KEYWORD is)($(D_KEYWORD int)[10] X : X[len], $(D_KEYWORD int) len : 5)); ) ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE )

$(LNAME2 specialkeywords, Special Keywords)

$(DDOC_BLANKLINE ) $(GRAMMAR $(GNAME SpecialKeyword): $(RELATIVE_LINK2 specialkeywords, $(D __FILE__)) $(RELATIVE_LINK2 specialkeywords, $(D __FILE_FULL_PATH__)) $(RELATIVE_LINK2 specialkeywords, $(D __MODULE__)) $(RELATIVE_LINK2 specialkeywords, $(D __LINE__)) $(RELATIVE_LINK2 specialkeywords, $(D __FUNCTION__)) $(RELATIVE_LINK2 specialkeywords, $(D __PRETTY_FUNCTION__)) ) $(DDOC_BLANKLINE ) $(DDOC_BLANKLINE ) $(P $(CODE __FILE__) and $(CODE __LINE__) expand to the source file name and line number at the point of instantiation. The path of the source file is left up to the compiler. ) $(DDOC_BLANKLINE ) $(P $(CODE __FILE_FULL_PATH__) expands to the absolute source file name at the point of instantiation.) $(DDOC_BLANKLINE ) $(P $(CODE __MODULE__) expands to the module name at the point of instantiation.) $(DDOC_BLANKLINE ) $(P $(CODE __FUNCTION__) expands to the fully qualified name of the function at the point of instantiation.) $(DDOC_BLANKLINE ) $(P $(CODE __PRETTY_FUNCTION__) is similar to $(CODE __FUNCTION__), but also expands the function return type, its parameter types, and its attributes.) $(DDOC_BLANKLINE ) $(P Example:) $(DDOC_BLANKLINE ) $(SPEC_RUNNABLE_EXAMPLE_COMPILE $(D_CODE $(D_KEYWORD module) test; $(D_KEYWORD import) std.stdio; $(D_KEYWORD void) test(string file = $(D_KEYWORD __FILE__), size_t line = $(D_KEYWORD __LINE__), string mod = $(D_KEYWORD __MODULE__), string func = $(D_KEYWORD __FUNCTION__), string pretty = $(D_KEYWORD __PRETTY_FUNCTION__), string fileFullPath = $(D_KEYWORD __FILE_FULL_PATH__)) { writefln($(D_STRING "file: '%s', line: '%s', module: '%s',\nfunction: '%s', ") ~ $(D_STRING "pretty function: '%s',\nfile full path: '%s'"), file, line, mod, func, pretty, fileFullPath); } $(D_KEYWORD int) main(string[] args) { test(); $(D_KEYWORD return) 0; } ) ) $(DDOC_BLANKLINE ) $(P Assuming the file was at /example/test.d, this will output:) $(DDOC_BLANKLINE ) $(CONSOLE file: 'test.d', line: '13', module: 'test', function: 'test.main', pretty function: 'int test.main(string[] args)', file full path: '/example/test.d' ) $(DDOC_BLANKLINE )

$(LNAME2 associativity, Associativity and Commutativity)

$(DDOC_BLANKLINE ) $(P An implementation may rearrange the evaluation of expressions according to arithmetic associativity and commutativity rules as long as, within that thread of execution, no observable difference is possible. ) $(DDOC_BLANKLINE ) $(P This rule precludes any associative or commutative reordering of floating point expressions. ) $(SPEC_SUBNAV_PREV_NEXT pragma, Pragmas, statement, Statements) ) )