| 1 |
Ddoc |
|---|
| 2 |
|
|---|
| 3 |
$(SPEC_S Expressions, |
|---|
| 4 |
|
|---|
| 5 |
$(P C and C++ programmers will find the D expressions very familiar, |
|---|
| 6 |
with a few interesting additions. |
|---|
| 7 |
) |
|---|
| 8 |
|
|---|
| 9 |
$(P Expressions are used to compute values with a resulting type. |
|---|
| 10 |
These values can then be assigned, |
|---|
| 11 |
tested, or ignored. Expressions can also have side effects. |
|---|
| 12 |
) |
|---|
| 13 |
|
|---|
| 14 |
<h2><a name="order-of-evaluation">Order Of Evaluation</a></h2> |
|---|
| 15 |
|
|---|
| 16 |
$(P The following binary expressions are evaluated in strictly |
|---|
| 17 |
left-to-right order:) |
|---|
| 18 |
|
|---|
| 19 |
$(P |
|---|
| 20 |
$(V2 |
|---|
| 21 |
$(GLINK OrExpression), |
|---|
| 22 |
$(GLINK XorExpression), |
|---|
| 23 |
$(GLINK AndExpression), |
|---|
| 24 |
$(GLINK CmpExpression), |
|---|
| 25 |
$(GLINK ShiftExpression), |
|---|
| 26 |
$(GLINK AddExpression), |
|---|
| 27 |
$(GLINK CatExpression), |
|---|
| 28 |
$(GLINK MulExpression), |
|---|
| 29 |
$(GLINK PowExpression), |
|---|
| 30 |
) |
|---|
| 31 |
$(GLINK CommaExpression), |
|---|
| 32 |
$(GLINK OrOrExpression), |
|---|
| 33 |
$(GLINK AndAndExpression) |
|---|
| 34 |
) |
|---|
| 35 |
|
|---|
| 36 |
$(P The following binary expressions are evaluated in an |
|---|
| 37 |
implementation-defined order:) |
|---|
| 38 |
|
|---|
| 39 |
$(P |
|---|
| 40 |
$(GLINK AssignExpression), |
|---|
| 41 |
$(V1 |
|---|
| 42 |
$(GLINK OrExpression), |
|---|
| 43 |
$(GLINK XorExpression), |
|---|
| 44 |
$(GLINK AndExpression), |
|---|
| 45 |
$(GLINK CmpExpression), |
|---|
| 46 |
$(GLINK ShiftExpression), |
|---|
| 47 |
$(GLINK AddExpression), |
|---|
| 48 |
$(GLINK CatExpression), |
|---|
| 49 |
$(GLINK MulExpression), |
|---|
| 50 |
) |
|---|
| 51 |
function parameters |
|---|
| 52 |
) |
|---|
| 53 |
|
|---|
| 54 |
$(P It is an error |
|---|
| 55 |
to depend on order of evaluation when it is not specified. |
|---|
| 56 |
For example, the following are illegal: |
|---|
| 57 |
) |
|---|
| 58 |
------------- |
|---|
| 59 |
i = i++; |
|---|
| 60 |
c = a + (a = b); |
|---|
| 61 |
func(++i, ++i); |
|---|
| 62 |
------------- |
|---|
| 63 |
$(P If the compiler can determine that the result of an expression |
|---|
| 64 |
is illegally dependent on the order of evaluation, it can issue |
|---|
| 65 |
an error (but is not required to). The ability to detect these kinds |
|---|
| 66 |
of errors is a quality of implementation issue. |
|---|
| 67 |
) |
|---|
| 68 |
|
|---|
| 69 |
<h2><a name="Expression">Expressions</a></h2> |
|---|
| 70 |
|
|---|
| 71 |
$(GRAMMAR |
|---|
| 72 |
$(GNAME Expression): |
|---|
| 73 |
$(GLINK AssignExpression) |
|---|
| 74 |
$(GLINK AssignExpression) $(B ,) $(I Expression) |
|---|
| 75 |
) |
|---|
| 76 |
|
|---|
| 77 |
The left operand of the $(B ,) is evaluated, then the right operand |
|---|
| 78 |
is evaluated. The type of the expression is the type of the right |
|---|
| 79 |
operand, and the result is the result of the right operand. |
|---|
| 80 |
|
|---|
| 81 |
|
|---|
| 82 |
<h2>Assign Expressions</h2> |
|---|
| 83 |
|
|---|
| 84 |
$(GRAMMAR |
|---|
| 85 |
$(GNAME AssignExpression): |
|---|
| 86 |
$(GLINK ConditionalExpression) |
|---|
| 87 |
$(GLINK ConditionalExpression) $(B =) $(I AssignExpression) |
|---|
| 88 |
$(GLINK ConditionalExpression) $(B +=) $(I AssignExpression) |
|---|
| 89 |
$(GLINK ConditionalExpression) $(B -=) $(I AssignExpression) |
|---|
| 90 |
$(GLINK ConditionalExpression) $(B *=) $(I AssignExpression) |
|---|
| 91 |
$(GLINK ConditionalExpression) $(B /=) $(I AssignExpression) |
|---|
| 92 |
$(GLINK ConditionalExpression) $(B %=) $(I AssignExpression) |
|---|
| 93 |
$(GLINK ConditionalExpression) $(B &=) $(I AssignExpression) |
|---|
| 94 |
$(GLINK ConditionalExpression) $(B |=) $(I AssignExpression) |
|---|
| 95 |
$(GLINK ConditionalExpression) $(B ^=) $(I AssignExpression) |
|---|
| 96 |
$(GLINK ConditionalExpression) $(B ~=) $(I AssignExpression) |
|---|
| 97 |
$(GLINK ConditionalExpression) $(B <<=) $(I AssignExpression) |
|---|
| 98 |
$(GLINK ConditionalExpression) $(B >>=) $(I AssignExpression) |
|---|
| 99 |
$(GLINK ConditionalExpression) $(B >>>=) $(I AssignExpression) |
|---|
| 100 |
$(V2 |
|---|
| 101 |
$(GLINK ConditionalExpression) $(B ^^=) $(I AssignExpression)) |
|---|
| 102 |
) |
|---|
| 103 |
|
|---|
| 104 |
The right operand is implicitly converted to the type of the |
|---|
| 105 |
left operand, and assigned to it. The result type is the type |
|---|
| 106 |
of the lvalue, and the result value is the value of the lvalue |
|---|
| 107 |
after the assignment. |
|---|
| 108 |
<p> |
|---|
| 109 |
|
|---|
| 110 |
The left operand must be an lvalue. |
|---|
| 111 |
|
|---|
| 112 |
<h3>Assignment Operator Expressions</h3> |
|---|
| 113 |
|
|---|
| 114 |
Assignment operator expressions, such as: |
|---|
| 115 |
|
|---|
| 116 |
-------------- |
|---|
| 117 |
$(I a op= b) |
|---|
| 118 |
-------------- |
|---|
| 119 |
|
|---|
| 120 |
are semantically equivalent to: |
|---|
| 121 |
|
|---|
| 122 |
-------------- |
|---|
| 123 |
$(I a = a op b) |
|---|
| 124 |
-------------- |
|---|
| 125 |
|
|---|
| 126 |
except that operand $(I a) is only evaluated once. |
|---|
| 127 |
|
|---|
| 128 |
<h2>Conditional Expressions</h2> |
|---|
| 129 |
|
|---|
| 130 |
$(GRAMMAR |
|---|
| 131 |
$(GNAME ConditionalExpression): |
|---|
| 132 |
$(GLINK OrOrExpression) |
|---|
| 133 |
$(GLINK OrOrExpression) $(B ?) $(GLINK Expression) $(B :) $(I ConditionalExpression) |
|---|
| 134 |
) |
|---|
| 135 |
|
|---|
| 136 |
The first expression is converted to bool, and is evaluated. |
|---|
| 137 |
If it is true, then the second expression is evaluated, and |
|---|
| 138 |
its result is the result of the conditional expression. |
|---|
| 139 |
If it is false, then the third expression is evaluated, and |
|---|
| 140 |
its result is the result of the conditional expression. |
|---|
| 141 |
If either the second or third expressions are of type void, |
|---|
| 142 |
then the resulting type is void. Otherwise, the second and third |
|---|
| 143 |
expressions are implicitly converted to a common type which becomes |
|---|
| 144 |
the result type of the conditional expression. |
|---|
| 145 |
|
|---|
| 146 |
<h2>OrOr Expressions</h2> |
|---|
| 147 |
|
|---|
| 148 |
$(GRAMMAR |
|---|
| 149 |
$(GNAME OrOrExpression): |
|---|
| 150 |
$(GLINK AndAndExpression) |
|---|
| 151 |
$(I OrOrExpression) $(B ||) $(GLINK AndAndExpression) |
|---|
| 152 |
) |
|---|
| 153 |
|
|---|
| 154 |
The result type of an $(I OrOrExpression) is bool, |
|---|
| 155 |
unless the right operand |
|---|
| 156 |
has type void, when the result is type void. |
|---|
| 157 |
<p> |
|---|
| 158 |
|
|---|
| 159 |
The $(I OrOrExpression) evaluates its left operand. |
|---|
| 160 |
|
|---|
| 161 |
If the left operand, converted to type bool, evaluates to |
|---|
| 162 |
true, then the right operand is not evaluated. If the result type of |
|---|
| 163 |
the $(I OrOrExpression) is bool then the result of the |
|---|
| 164 |
expression is true. |
|---|
| 165 |
|
|---|
| 166 |
If the left operand is false, then the right |
|---|
| 167 |
operand is evaluated. |
|---|
| 168 |
If the result type of |
|---|
| 169 |
the $(I OrOrExpression) is bool then the result of the |
|---|
| 170 |
expression is the right operand converted to type bool. |
|---|
| 171 |
|
|---|
| 172 |
|
|---|
| 173 |
<h2>AndAnd Expressions</h2> |
|---|
| 174 |
|
|---|
| 175 |
$(V1 |
|---|
| 176 |
$(GRAMMAR |
|---|
| 177 |
$(GNAME AndAndExpression): |
|---|
| 178 |
$(GLINK OrExpression) |
|---|
| 179 |
$(I AndAndExpression) $(B &&) $(GLINK OrExpression) |
|---|
| 180 |
|
|---|
| 181 |
) |
|---|
| 182 |
) |
|---|
| 183 |
$(V2 |
|---|
| 184 |
$(GRAMMAR |
|---|
| 185 |
$(GNAME AndAndExpression): |
|---|
| 186 |
$(GLINK OrExpression) |
|---|
| 187 |
$(I AndAndExpression) $(B &&) $(GLINK OrExpression) |
|---|
| 188 |
$(GLINK CmpExpression) |
|---|
| 189 |
$(I AndAndExpression) $(B &&) $(GLINK CmpExpression) |
|---|
| 190 |
) |
|---|
| 191 |
) |
|---|
| 192 |
|
|---|
| 193 |
$(P The result type of an $(I AndAndExpression) is bool, unless the right operand |
|---|
| 194 |
has type void, when the result is type void. |
|---|
| 195 |
) |
|---|
| 196 |
|
|---|
| 197 |
$(P The $(I AndAndExpression) evaluates its left operand. |
|---|
| 198 |
) |
|---|
| 199 |
|
|---|
| 200 |
$(P If the left operand, converted to type bool, evaluates to |
|---|
| 201 |
false, then the right operand is not evaluated. If the result type of |
|---|
| 202 |
the $(I AndAndExpression) is bool then the result of the |
|---|
| 203 |
expression is false. |
|---|
| 204 |
) |
|---|
| 205 |
|
|---|
| 206 |
$(P If the left operand is true, then the right |
|---|
| 207 |
operand is evaluated. |
|---|
| 208 |
If the result type of |
|---|
| 209 |
the $(I AndAndExpression) is bool then the result of the |
|---|
| 210 |
expression is the right operand converted to type bool. |
|---|
| 211 |
) |
|---|
| 212 |
|
|---|
| 213 |
|
|---|
| 214 |
<h2>Bitwise Expressions</h2> |
|---|
| 215 |
|
|---|
| 216 |
Bit wise expressions perform a bitwise operation on their operands. |
|---|
| 217 |
Their operands must be integral types. |
|---|
| 218 |
First, the default integral promotions are done. Then, the bitwise |
|---|
| 219 |
operation is done. |
|---|
| 220 |
|
|---|
| 221 |
<h3>Or Expressions</h3> |
|---|
| 222 |
|
|---|
| 223 |
$(GRAMMAR |
|---|
| 224 |
$(GNAME OrExpression): |
|---|
| 225 |
$(GLINK XorExpression) |
|---|
| 226 |
$(I OrExpression) $(B |) $(GLINK XorExpression) |
|---|
| 227 |
) |
|---|
| 228 |
|
|---|
| 229 |
The operands are OR'd together. |
|---|
| 230 |
|
|---|
| 231 |
<h3>Xor Expressions</h3> |
|---|
| 232 |
|
|---|
| 233 |
$(GRAMMAR |
|---|
| 234 |
$(GNAME XorExpression): |
|---|
| 235 |
$(GLINK AndExpression) |
|---|
| 236 |
$(I XorExpression) $(B ^) $(GLINK AndExpression) |
|---|
| 237 |
) |
|---|
| 238 |
|
|---|
| 239 |
The operands are XOR'd together. |
|---|
| 240 |
|
|---|
| 241 |
<h3>And Expressions</h3> |
|---|
| 242 |
|
|---|
| 243 |
$(V1 |
|---|
| 244 |
$(GRAMMAR |
|---|
| 245 |
$(GNAME AndExpression): |
|---|
| 246 |
$(GLINK CmpExpression) |
|---|
| 247 |
$(I AndExpression) $(B &) $(GLINK CmpExpression) |
|---|
| 248 |
) |
|---|
| 249 |
) |
|---|
| 250 |
$(V2 |
|---|
| 251 |
$(GRAMMAR |
|---|
| 252 |
$(GNAME AndExpression): |
|---|
| 253 |
$(GLINK ShiftExpression) |
|---|
| 254 |
$(I AndExpression) $(B &) $(GLINK ShiftExpression) |
|---|
| 255 |
) |
|---|
| 256 |
) |
|---|
| 257 |
The operands are AND'd together. |
|---|
| 258 |
|
|---|
| 259 |
|
|---|
| 260 |
<h2><a name="CmpExpression">Compare Expressions</a></h2> |
|---|
| 261 |
|
|---|
| 262 |
$(GRAMMAR |
|---|
| 263 |
$(GNAME CmpExpression): |
|---|
| 264 |
$(GLINK ShiftExpression) |
|---|
| 265 |
$(GLINK EqualExpression) |
|---|
| 266 |
$(GLINK IdentityExpression) |
|---|
| 267 |
$(GLINK RelExpression) |
|---|
| 268 |
$(GLINK InExpression) |
|---|
| 269 |
) |
|---|
| 270 |
|
|---|
| 271 |
<h2><a name="EqualExpression">Equality Expressions</a></h2> |
|---|
| 272 |
|
|---|
| 273 |
$(GRAMMAR |
|---|
| 274 |
$(GNAME EqualExpression): |
|---|
| 275 |
$(GLINK ShiftExpression) $(B ==) $(GLINK ShiftExpression) |
|---|
| 276 |
$(GLINK ShiftExpression) $(B !=) $(GLINK ShiftExpression) |
|---|
| 277 |
) |
|---|
| 278 |
|
|---|
| 279 |
Equality expressions compare the two operands for equality ($(B ==)) |
|---|
| 280 |
or inequality ($(B !=)). |
|---|
| 281 |
The type of the result is bool. The operands |
|---|
| 282 |
go through the usual conversions to bring them to a common type before |
|---|
| 283 |
comparison. |
|---|
| 284 |
<p> |
|---|
| 285 |
|
|---|
| 286 |
If they are integral values or pointers, equality |
|---|
| 287 |
is defined as the bit pattern of the type matches exactly. |
|---|
| 288 |
Equality for struct objects means the bit patterns of the objects |
|---|
| 289 |
match exactly (the existence of alignment holes in the objects |
|---|
| 290 |
is accounted for, usually by setting them all to 0 upon |
|---|
| 291 |
initialization). |
|---|
| 292 |
Equality for floating point types is more complicated. -0 and |
|---|
| 293 |
+0 compare as equal. If either or both operands are NAN, then |
|---|
| 294 |
both the == returns false and != returns true. Otherwise, the bit |
|---|
| 295 |
patterns are compared for equality. |
|---|
| 296 |
<p> |
|---|
| 297 |
|
|---|
| 298 |
For complex numbers, equality is defined as equivalent to: |
|---|
| 299 |
|
|---|
| 300 |
<pre> |
|---|
| 301 |
x.re == y.re && x.im == y.im |
|---|
| 302 |
</pre> |
|---|
| 303 |
|
|---|
| 304 |
and inequality is defined as equivalent to: |
|---|
| 305 |
|
|---|
| 306 |
<pre> |
|---|
| 307 |
x.re != y.re || x.im != y.im |
|---|
| 308 |
</pre> |
|---|
| 309 |
|
|---|
| 310 |
$(P For class and struct objects, the expression $(TT (a == b)) |
|---|
| 311 |
is rewritten as |
|---|
| 312 |
$(TT a.opEquals(b)), and $(TT (a != b)) is rewritten as |
|---|
| 313 |
$(TT !a.opEquals(b)). |
|---|
| 314 |
) |
|---|
| 315 |
|
|---|
| 316 |
$(P For class objects, the $(CODE ==) and $(CODE !=) |
|---|
| 317 |
operators compare the |
|---|
| 318 |
contents of the objects. Therefore, comparing against |
|---|
| 319 |
$(CODE null) is invalid, as $(CODE null) has no contents. |
|---|
| 320 |
Use the $(CODE is) and $(CODE !is) operators instead. |
|---|
| 321 |
) |
|---|
| 322 |
|
|---|
| 323 |
--- |
|---|
| 324 |
class C; |
|---|
| 325 |
C c; |
|---|
| 326 |
if (c == null) // error |
|---|
| 327 |
... |
|---|
| 328 |
if (c is null) // ok |
|---|
| 329 |
... |
|---|
| 330 |
--- |
|---|
| 331 |
|
|---|
| 332 |
$(P For static and dynamic arrays, equality is defined as the |
|---|
| 333 |
lengths of the arrays |
|---|
| 334 |
matching, and all the elements are equal. |
|---|
| 335 |
) |
|---|
| 336 |
|
|---|
| 337 |
<h3><a name="IdentityExpression">Identity Expressions</a></h3> |
|---|
| 338 |
|
|---|
| 339 |
$(GRAMMAR |
|---|
| 340 |
$(GNAME IdentityExpression): |
|---|
| 341 |
$(GLINK ShiftExpression) $(B is) $(GLINK ShiftExpression) |
|---|
| 342 |
$(GLINK ShiftExpression) $(B !is) $(GLINK ShiftExpression) |
|---|
| 343 |
) |
|---|
| 344 |
|
|---|
| 345 |
$(P The $(B is) compares for identity. |
|---|
| 346 |
To compare for not identity, use $(TT $(I e1) $(B !is) $(I e2)). |
|---|
| 347 |
The type of the result is bool. The operands |
|---|
| 348 |
go through the usual conversions to bring them to a common type before |
|---|
| 349 |
comparison. |
|---|
| 350 |
) |
|---|
| 351 |
|
|---|
| 352 |
$(P For class objects, identity is defined as the object references |
|---|
| 353 |
are for the same object. Null class objects can be compared with |
|---|
| 354 |
$(B is). |
|---|
| 355 |
) |
|---|
| 356 |
|
|---|
| 357 |
$(P For struct objects, identity is defined as the bits in the |
|---|
| 358 |
struct being identical. |
|---|
| 359 |
) |
|---|
| 360 |
|
|---|
| 361 |
$(P For static and dynamic arrays, identity is defined as referring |
|---|
| 362 |
to the same array elements and the same number of elements. |
|---|
| 363 |
) |
|---|
| 364 |
|
|---|
| 365 |
$(P For other operand types, identity is defined as being the same |
|---|
| 366 |
as equality. |
|---|
| 367 |
) |
|---|
| 368 |
|
|---|
| 369 |
$(P The identity operator $(B is) cannot be overloaded. |
|---|
| 370 |
) |
|---|
| 371 |
|
|---|
| 372 |
<h2>Relational Expressions</h2> |
|---|
| 373 |
|
|---|
| 374 |
$(GRAMMAR |
|---|
| 375 |
$(GNAME RelExpression): |
|---|
| 376 |
$(GLINK ShiftExpression) $(B <) $(GLINK ShiftExpression) |
|---|
| 377 |
$(GLINK ShiftExpression) $(B <=) $(GLINK ShiftExpression) |
|---|
| 378 |
$(GLINK ShiftExpression) $(B >) $(GLINK ShiftExpression) |
|---|
| 379 |
$(GLINK ShiftExpression) $(B >=) $(GLINK ShiftExpression) |
|---|
| 380 |
$(GLINK ShiftExpression) $(B !<>=) $(GLINK ShiftExpression) |
|---|
| 381 |
$(GLINK ShiftExpression) $(B !<>) $(GLINK ShiftExpression) |
|---|
| 382 |
$(GLINK ShiftExpression) $(B <>) $(GLINK ShiftExpression) |
|---|
| 383 |
$(GLINK ShiftExpression) $(B <>=) $(GLINK ShiftExpression) |
|---|
| 384 |
$(GLINK ShiftExpression) $(B !>) $(GLINK ShiftExpression) |
|---|
| 385 |
$(GLINK ShiftExpression) $(B !>=) $(GLINK ShiftExpression) |
|---|
| 386 |
$(GLINK ShiftExpression) $(B !<) $(GLINK ShiftExpression) |
|---|
| 387 |
$(GLINK ShiftExpression) $(B !<=) $(GLINK ShiftExpression) |
|---|
| 388 |
) |
|---|
| 389 |
|
|---|
| 390 |
First, the integral promotions are done on the operands. |
|---|
| 391 |
The result type of a relational expression is bool. |
|---|
| 392 |
<p> |
|---|
| 393 |
|
|---|
| 394 |
For class objects, the result of Object.opCmp() forms the left |
|---|
| 395 |
operand, and 0 forms the right operand. The result of the |
|---|
| 396 |
relational expression (o1 op o2) is: |
|---|
| 397 |
|
|---|
| 398 |
<pre> |
|---|
| 399 |
(o1.opCmp(o2) op 0) |
|---|
| 400 |
</pre> |
|---|
| 401 |
|
|---|
| 402 |
It is an error to compare objects if one is $(B null). |
|---|
| 403 |
<p> |
|---|
| 404 |
|
|---|
| 405 |
For static and dynamic arrays, the result of the relational |
|---|
| 406 |
op is the result of the operator applied to the first non-equal |
|---|
| 407 |
element of the array. If two arrays compare equal, but are of |
|---|
| 408 |
different lengths, the shorter array compares as "less" than the |
|---|
| 409 |
longer array. |
|---|
| 410 |
|
|---|
| 411 |
|
|---|
| 412 |
<h3>Integer comparisons</h3> |
|---|
| 413 |
|
|---|
| 414 |
$(P Integer comparisons happen when both operands are integral |
|---|
| 415 |
types. |
|---|
| 416 |
) |
|---|
| 417 |
|
|---|
| 418 |
$(TABLE1 |
|---|
| 419 |
<caption>Integer comparison operators</caption> |
|---|
| 420 |
$(TR |
|---|
| 421 |
$(TH Operator)$(TH Relation) |
|---|
| 422 |
)$(TR |
|---|
| 423 |
$(TD <) $(TD less) |
|---|
| 424 |
)$(TR |
|---|
| 425 |
$(TD >) $(TD greater) |
|---|
| 426 |
)$(TR |
|---|
| 427 |
$(TD <=) $(TD less or equal) |
|---|
| 428 |
)$(TR |
|---|
| 429 |
$(TD >=) $(TD greater or equal) |
|---|
| 430 |
)$(TR |
|---|
| 431 |
$(TD ==) $(TD equal) |
|---|
| 432 |
)$(TR |
|---|
| 433 |
$(TD !=) $(TD not equal) |
|---|
| 434 |
) |
|---|
| 435 |
) |
|---|
| 436 |
|
|---|
| 437 |
$(P It is an error to have one operand be signed and the other |
|---|
| 438 |
unsigned for a <, <=, > or >= expression. |
|---|
| 439 |
Use casts to make both operands signed or both operands unsigned. |
|---|
| 440 |
) |
|---|
| 441 |
|
|---|
| 442 |
<h3><a name="floating_point_comparisons">Floating point comparisons</a></h3> |
|---|
| 443 |
|
|---|
| 444 |
If one or both operands are floating point, then a floating |
|---|
| 445 |
point comparison is performed. |
|---|
| 446 |
<p> |
|---|
| 447 |
|
|---|
| 448 |
Useful floating point operations must take into account NAN values. |
|---|
| 449 |
In particular, a relational operator can have NAN operands. |
|---|
| 450 |
The result of a relational operation on float |
|---|
| 451 |
values is less, greater, equal, or unordered (unordered means |
|---|
| 452 |
either or both of the |
|---|
| 453 |
operands is a NAN). That means there are 14 possible comparison |
|---|
| 454 |
conditions to test for: |
|---|
| 455 |
<p> |
|---|
| 456 |
|
|---|
| 457 |
$(TABLE1 |
|---|
| 458 |
<caption>Floating point comparison operators</caption> |
|---|
| 459 |
$(TR |
|---|
| 460 |
$(TH Operator) |
|---|
| 461 |
$(TH Greater Than) |
|---|
| 462 |
$(TH Less Than) |
|---|
| 463 |
$(TH Equal) |
|---|
| 464 |
$(TH Unordered) |
|---|
| 465 |
$(TH Exception) |
|---|
| 466 |
$(TH Relation) |
|---|
| 467 |
) |
|---|
| 468 |
$(TR |
|---|
| 469 |
$(TD ==) $(TD F)$(TD F)$(TD T)$(TD F)$(TD no) $(TD equal) |
|---|
| 470 |
) |
|---|
| 471 |
$(TR |
|---|
| 472 |
$(TD !=) $(TD T)$(TD T)$(TD F)$(TD T)$(TD no) $(TD unordered, less, or greater) |
|---|
| 473 |
) |
|---|
| 474 |
$(TR |
|---|
| 475 |
$(TD >) $(TD T)$(TD F)$(TD F)$(TD F)$(TD yes) $(TD greater) |
|---|
| 476 |
) |
|---|
| 477 |
$(TR |
|---|
| 478 |
$(TD >=) $(TD T)$(TD F)$(TD T)$(TD F)$(TD yes) $(TD greater or equal) |
|---|
| 479 |
) |
|---|
| 480 |
$(TR |
|---|
| 481 |
$(TD <) $(TD F)$(TD T)$(TD F)$(TD F)$(TD yes) $(TD less) |
|---|
| 482 |
) |
|---|
| 483 |
$(TR |
|---|
| 484 |
$(TD <=) $(TD F)$(TD T)$(TD T)$(TD F)$(TD yes) $(TD less or equal) |
|---|
| 485 |
) |
|---|
| 486 |
$(TR |
|---|
| 487 |
$(TD !<>=) $(TD F)$(TD F)$(TD F)$(TD T)$(TD no) $(TD unordered) |
|---|
| 488 |
) |
|---|
| 489 |
$(TR |
|---|
| 490 |
$(TD <>) $(TD T)$(TD T)$(TD F)$(TD F)$(TD yes) $(TD less or greater) |
|---|
| 491 |
) |
|---|
| 492 |
$(TR |
|---|
| 493 |
$(TD <>=) $(TD T)$(TD T)$(TD T)$(TD F)$(TD yes) $(TD less, equal, or greater) |
|---|
| 494 |
) |
|---|
| 495 |
$(TR |
|---|
| 496 |
$(TD !<=) $(TD T)$(TD F)$(TD F)$(TD T)$(TD no) $(TD unordered or greater) |
|---|
| 497 |
) |
|---|
| 498 |
$(TR |
|---|
| 499 |
$(TD !<) $(TD T)$(TD F)$(TD T)$(TD T)$(TD no) $(TD unordered, greater, or equal) |
|---|
| 500 |
) |
|---|
| 501 |
$(TR |
|---|
| 502 |
$(TD !>=) $(TD F)$(TD T)$(TD F)$(TD T)$(TD no) $(TD unordered or less) |
|---|
| 503 |
) |
|---|
| 504 |
$(TR |
|---|
| 505 |
$(TD !>) $(TD F)$(TD T)$(TD T)$(TD T)$(TD no) $(TD unordered, less, or equal) |
|---|
| 506 |
) |
|---|
| 507 |
$(TR |
|---|
| 508 |
$(TD !<>) $(TD F)$(TD F)$(TD T)$(TD T)$(TD no) $(TD unordered or equal) |
|---|
| 509 |
) |
|---|
| 510 |
) |
|---|
| 511 |
|
|---|
| 512 |
<h4>Notes:</h4> |
|---|
| 513 |
|
|---|
| 514 |
$(OL |
|---|
| 515 |
$(LI For floating point comparison operators, |
|---|
| 516 |
$(CODE ($(I a) !$(I op) $(I b))) |
|---|
| 517 |
is not the same as $(CODE !($(I a op b))).) |
|---|
| 518 |
$(LI "Unordered" means one or both of the operands is a NAN.) |
|---|
| 519 |
$(LI "Exception" means the $(I Invalid Exception) is raised if one |
|---|
| 520 |
of the operands is a NAN. It does not mean an exception |
|---|
| 521 |
is thrown. The $(I Invalid Exception) can be checked |
|---|
| 522 |
using the functions in $(LINK2 phobos/std_c_fenv.html, std.c.fenv). |
|---|
| 523 |
) |
|---|
| 524 |
) |
|---|
| 525 |
|
|---|
| 526 |
<h3><a name="class_comparisons">Class comparisons</a></h3> |
|---|
| 527 |
|
|---|
| 528 |
$(P For class objects, the relational |
|---|
| 529 |
operators compare the |
|---|
| 530 |
contents of the objects. Therefore, comparing against |
|---|
| 531 |
$(CODE null) is invalid, as $(CODE null) has no contents. |
|---|
| 532 |
) |
|---|
| 533 |
|
|---|
| 534 |
--- |
|---|
| 535 |
class C; |
|---|
| 536 |
C c; |
|---|
| 537 |
if (c < null) // error |
|---|
| 538 |
... |
|---|
| 539 |
--- |
|---|
| 540 |
|
|---|
| 541 |
<h2><a name="InExpression">In Expressions</a></h2> |
|---|
| 542 |
|
|---|
| 543 |
$(GRAMMAR |
|---|
| 544 |
$(GNAME InExpression): |
|---|
| 545 |
$(GLINK ShiftExpression) $(B in) $(GLINK ShiftExpression) |
|---|
| 546 |
$(GLINK ShiftExpression) $(B !in) $(GLINK ShiftExpression) |
|---|
| 547 |
) |
|---|
| 548 |
|
|---|
| 549 |
$(P An associative array can be tested to see if an element is in the array: |
|---|
| 550 |
) |
|---|
| 551 |
|
|---|
| 552 |
------------- |
|---|
| 553 |
int foo[char[]]; |
|---|
| 554 |
... |
|---|
| 555 |
if ("hello" in foo) |
|---|
| 556 |
... |
|---|
| 557 |
------------- |
|---|
| 558 |
|
|---|
| 559 |
$(P The $(B in) expression has the same precedence as the |
|---|
| 560 |
relational expressions $(B <), $(B <=), |
|---|
| 561 |
etc. |
|---|
| 562 |
The return value of the $(I InExpression) is $(B null) |
|---|
| 563 |
if the element is not in the array; |
|---|
| 564 |
if it is in the array it is a pointer to the element. |
|---|
| 565 |
) |
|---|
| 566 |
|
|---|
| 567 |
$(P The $(B !in) expression is the logical negation of the $(B in) |
|---|
| 568 |
operation. |
|---|
| 569 |
) |
|---|
| 570 |
|
|---|
| 571 |
<h2>Shift Expressions</h2> |
|---|
| 572 |
|
|---|
| 573 |
$(GRAMMAR |
|---|
| 574 |
$(GNAME ShiftExpression): |
|---|
| 575 |
$(GLINK AddExpression) |
|---|
| 576 |
$(I ShiftExpression) $(B <<) $(GLINK AddExpression) |
|---|
| 577 |
$(I ShiftExpression) $(B >>) $(GLINK AddExpression) |
|---|
| 578 |
$(I ShiftExpression) $(B >>>) $(GLINK AddExpression) |
|---|
| 579 |
) |
|---|
| 580 |
|
|---|
| 581 |
The operands must be integral types, and undergo the usual integral |
|---|
| 582 |
promotions. The result type is the type of the left operand after |
|---|
| 583 |
the promotions. The result value is the result of shifting the bits |
|---|
| 584 |
by the right operand's value. |
|---|
| 585 |
<p> |
|---|
| 586 |
|
|---|
| 587 |
$(B <<) is a left shift. |
|---|
| 588 |
$(B >>) is a signed right shift. |
|---|
| 589 |
$(B >>>) is an unsigned right shift. |
|---|
| 590 |
<p> |
|---|
| 591 |
|
|---|
| 592 |
It's illegal to shift by more bits than the size of the |
|---|
| 593 |
quantity being shifted: |
|---|
| 594 |
|
|---|
| 595 |
------------- |
|---|
| 596 |
int c; |
|---|
| 597 |
c << 33; // error |
|---|
| 598 |
------------- |
|---|
| 599 |
|
|---|
| 600 |
<h2>Add Expressions</h2> |
|---|
| 601 |
|
|---|
| 602 |
$(GRAMMAR |
|---|
| 603 |
$(GNAME AddExpression): |
|---|
| 604 |
$(GLINK MulExpression) |
|---|
| 605 |
$(I AddExpression) $(B +) $(GLINK MulExpression) |
|---|
| 606 |
$(I AddExpression) $(B -) $(GLINK MulExpression) |
|---|
| 607 |
$(GLINK CatExpression) |
|---|
| 608 |
) |
|---|
| 609 |
|
|---|
| 610 |
$(P If the operands are of integral types, they undergo integral |
|---|
| 611 |
promotions, and then are brought to a common type using the |
|---|
| 612 |
usual arithmetic conversions. |
|---|
| 613 |
) |
|---|
| 614 |
|
|---|
| 615 |
$(P If either operand is a floating point type, the other is implicitly |
|---|
| 616 |
converted to floating point and they are brought to a common type |
|---|
| 617 |
via the usual arithmetic conversions. |
|---|
| 618 |
) |
|---|
| 619 |
|
|---|
| 620 |
$(P If the operator is $(B +) or $(B -), and |
|---|
| 621 |
the first operand is a pointer, and the second is an integral type, |
|---|
| 622 |
the resulting type is the type of the first operand, and the resulting |
|---|
| 623 |
value is the pointer plus (or minus) the second operand multiplied by |
|---|
| 624 |
the size of the type pointed to by the first operand. |
|---|
| 625 |
) |
|---|
| 626 |
|
|---|
| 627 |
$(P If the second operand is a pointer, and the first is an integral type, |
|---|
| 628 |
and the operator is $(B +), |
|---|
| 629 |
the operands are reversed and the pointer arithmetic just described |
|---|
| 630 |
is applied. |
|---|
| 631 |
) |
|---|
| 632 |
|
|---|
| 633 |
$(P If both operands are pointers, and the operator is $(B +), |
|---|
| 634 |
then it is illegal. For $(B -), the pointers are subtracted and the |
|---|
| 635 |
result is divided by the size of the type pointed to by the |
|---|
| 636 |
operands. It is an error if the pointers point to different types. |
|---|
| 637 |
) |
|---|
| 638 |
|
|---|
| 639 |
$(P Add expressions for floating point operands are not associative. |
|---|
| 640 |
) |
|---|
| 641 |
|
|---|
| 642 |
<h2>Cat Expressions</h2> |
|---|
| 643 |
|
|---|
| 644 |
$(GRAMMAR |
|---|
| 645 |
$(GNAME CatExpression): |
|---|
| 646 |
$(I AddExpression) $(B ~) $(GLINK MulExpression) |
|---|
| 647 |
) |
|---|
| 648 |
|
|---|
| 649 |
$(P A $(I CatExpression) concatenates arrays, producing |
|---|
| 650 |
a dynmaic array with the result. The arrays must be |
|---|
| 651 |
arrays of the same element type. If one operand is an array |
|---|
| 652 |
and the other is of that array's element type, that element |
|---|
| 653 |
is converted to an array of length 1 of that element, |
|---|
| 654 |
and then the concatenation is performed. |
|---|
| 655 |
) |
|---|
| 656 |
|
|---|
| 657 |
<h2>Mul Expressions</h2> |
|---|
| 658 |
|
|---|
| 659 |
$(V1 |
|---|
| 660 |
$(GRAMMAR |
|---|
| 661 |
$(GNAME MulExpression): |
|---|
| 662 |
$(GLINK UnaryExpression) |
|---|
| 663 |
$(I MulExpression) $(B *) $(GLINK UnaryExpression) |
|---|
| 664 |
$(I MulExpression) $(B /) $(GLINK UnaryExpression) |
|---|
| 665 |
$(I MulExpression) $(B %) $(GLINK UnaryExpression) |
|---|
| 666 |
) |
|---|
| 667 |
) |
|---|
| 668 |
|
|---|
| 669 |
$(P The operands must be arithmetic types. They undergo integral |
|---|
| 670 |
promotions, and then are brought to a common type using the |
|---|
| 671 |
usual arithmetic conversions. |
|---|
| 672 |
) |
|---|
| 673 |
|
|---|
| 674 |
$(P For integral operands, the $(B *), $(B /), and $(B %) |
|---|
| 675 |
correspond to multiply, divide, and modulus operations. |
|---|
| 676 |
For multiply, overflows are ignored and simply chopped to fit |
|---|
| 677 |
into the integral type. |
|---|
| 678 |
) |
|---|
| 679 |
|
|---|
| 680 |
$(P For integral operands of the $(B /) and $(B %) operators, |
|---|
| 681 |
the quotient rounds towards zero and the remainder has the |
|---|
| 682 |
same sign as the dividend. |
|---|
| 683 |
If the divisor is zero, an Exception is thrown. |
|---|
| 684 |
) |
|---|
| 685 |
|
|---|
| 686 |
$(P For floating point operands, the * and / operations correspond |
|---|
| 687 |
to the IEEE 754 floating point equivalents. % is not the same as |
|---|
| 688 |
the IEEE 754 remainder. For example, 15.0 % 10.0 == 5.0, whereas |
|---|
| 689 |
for IEEE 754, remainder(15.0,10.0) == -5.0. |
|---|
| 690 |
) |
|---|
| 691 |
|
|---|
| 692 |
$(P Mul expressions for floating point operands are not associative. |
|---|
| 693 |
) |
|---|
| 694 |
|
|---|
| 695 |
<h2><a name="UnaryExpression">Unary Expressions</a></h2> |
|---|
| 696 |
|
|---|
| 697 |
$(GRAMMAR |
|---|
| 698 |
$(GNAME UnaryExpression): |
|---|
| 699 |
$(V1 $(GLINK PostfixExpression))$(V2 $(GLINK PowExpression)) |
|---|
| 700 |
$(B &) $(I UnaryExpression) |
|---|
| 701 |
$(B ++) $(I UnaryExpression) |
|---|
| 702 |
$(B --) $(I UnaryExpression) |
|---|
| 703 |
$(B *) $(I UnaryExpression) |
|---|
| 704 |
$(B -) $(I UnaryExpression) |
|---|
| 705 |
$(B +) $(I UnaryExpression) |
|---|
| 706 |
$(B !) $(I UnaryExpression) |
|---|
| 707 |
$(B ~) $(I UnaryExpression) |
|---|
| 708 |
$(B $(LPAREN)) $(GLINK2 declaration, Type) $(B $(RPAREN) .) $(I Identifier) |
|---|
| 709 |
$(GLINK NewExpression) |
|---|
| 710 |
$(GLINK DeleteExpression) |
|---|
| 711 |
$(GLINK CastExpression) |
|---|
| 712 |
$(LINK2 class.html#anonymous, $(I NewAnonClassExpression)) |
|---|
| 713 |
) |
|---|
| 714 |
|
|---|
| 715 |
|
|---|
| 716 |
<h3>New Expressions</h3> |
|---|
| 717 |
|
|---|
| 718 |
$(GRAMMAR |
|---|
| 719 |
$(GNAME NewExpression): |
|---|
| 720 |
$(I NewArguments) $(LINK2 declaration.html#Type, $(I Type)) $(B [) $(GLINK AssignExpression) $(B ]) |
|---|
| 721 |
$(I NewArguments) $(LINK2 declaration.html#Type, $(I Type)) $(B $(LPAREN)) $(GLINK ArgumentList) $(B $(RPAREN)) |
|---|
| 722 |
$(I NewArguments) $(LINK2 declaration.html#Type, $(I Type)) |
|---|
| 723 |
$(I NewArguments) $(I ClassArguments) $(GLINK BaseClasslist)$(OPT) $(B {) $(GLINK DeclDefs) $(B } ) |
|---|
| 724 |
|
|---|
| 725 |
$(GNAME NewArguments): |
|---|
| 726 |
$(B new $(LPAREN)) $(GLINK ArgumentList) $(B $(RPAREN)) |
|---|
| 727 |
$(B new ( )) |
|---|
| 728 |
$(B new) |
|---|
| 729 |
|
|---|
| 730 |
$(GNAME ClassArguments): |
|---|
| 731 |
$(B class $(LPAREN)) $(GLINK ArgumentList) $(B $(RPAREN)) |
|---|
| 732 |
$(B class ( )) |
|---|
| 733 |
$(B class) |
|---|
| 734 |
|
|---|
| 735 |
$(GNAME ArgumentList): |
|---|
| 736 |
$(GLINK AssignExpression) |
|---|
| 737 |
$(V2 $(GLINK AssignExpression) $(B ,) |
|---|
| 738 |
) $(GLINK AssignExpression) $(B ,) $(I ArgumentList) |
|---|
| 739 |
) |
|---|
| 740 |
|
|---|
| 741 |
$(P $(I NewExpression)s are used to allocate memory on the garbage |
|---|
| 742 |
collected heap (default) or using a class or struct specific allocator. |
|---|
| 743 |
) |
|---|
| 744 |
|
|---|
| 745 |
$(P To allocate multidimensional arrays, the declaration reads |
|---|
| 746 |
in the same order as the prefix array declaration order. |
|---|
| 747 |
) |
|---|
| 748 |
|
|---|
| 749 |
------------- |
|---|
| 750 |
char[][] foo; // dynamic array of strings |
|---|
| 751 |
... |
|---|
| 752 |
foo = new char[][30]; // allocate array of 30 strings |
|---|
| 753 |
------------- |
|---|
| 754 |
|
|---|
| 755 |
$(P The above allocation can also be written as:) |
|---|
| 756 |
|
|---|
| 757 |
------------- |
|---|
| 758 |
foo = new char[][](30); // allocate array of 30 strings |
|---|
| 759 |
------------- |
|---|
| 760 |
|
|---|
| 761 |
$(P To allocate the nested arrays, multiple arguments can be used:) |
|---|
| 762 |
|
|---|
| 763 |
--------------- |
|---|
| 764 |
int[][][] bar; |
|---|
| 765 |
... |
|---|
| 766 |
bar = new int[][][](5,20,30); |
|---|
| 767 |
--------------- |
|---|
| 768 |
|
|---|
| 769 |
$(P Which is equivalent to:) |
|---|
| 770 |
|
|---|
| 771 |
---------- |
|---|
| 772 |
bar = new int[][][5]; |
|---|
| 773 |
foreach (ref a; bar) |
|---|
| 774 |
{ |
|---|
| 775 |
a = new int[][20]; |
|---|
| 776 |
foreach (ref b; a) |
|---|
| 777 |
{ |
|---|
| 778 |
b = new int[30]; |
|---|
| 779 |
} |
|---|
| 780 |
} |
|---|
| 781 |
----------- |
|---|
| 782 |
|
|---|
| 783 |
$(P If there is a $(B new $(LPAREN)) $(GLINK ArgumentList) $(B $(RPAREN)), |
|---|
| 784 |
then |
|---|
| 785 |
those arguments are passed to the class or struct specific allocator |
|---|
| 786 |
function after the size argument. |
|---|
| 787 |
) |
|---|
| 788 |
|
|---|
| 789 |
$(P If a $(I NewExpression) is used as an initializer for |
|---|
| 790 |
a function local variable with $(B scope) storage class, |
|---|
| 791 |
and the $(GLINK ArgumentList) to $(B new) is empty, then |
|---|
| 792 |
the instance is allocated on the stack rather than the heap |
|---|
| 793 |
or using the class specific allocator. |
|---|
| 794 |
) |
|---|
| 795 |
|
|---|
| 796 |
<h3>Delete Expressions</h3> |
|---|
| 797 |
|
|---|
| 798 |
$(GRAMMAR |
|---|
| 799 |
$(GNAME DeleteExpression): |
|---|
| 800 |
$(B delete) $(GLINK UnaryExpression) |
|---|
| 801 |
) |
|---|
| 802 |
$(P If the $(I UnaryExpression) is a class object reference, and |
|---|
| 803 |
there is a destructor for that class, the destructor |
|---|
| 804 |
is called for that object instance. |
|---|
| 805 |
) |
|---|
| 806 |
|
|---|
| 807 |
$(P Next, if the $(I UnaryExpression) is a class object reference, or |
|---|
| 808 |
a pointer to a struct instance, and the class or struct |
|---|
| 809 |
has overloaded operator delete, then that operator delete is called |
|---|
| 810 |
for that class object instance or struct instance. |
|---|
| 811 |
) |
|---|
| 812 |
|
|---|
| 813 |
$(P Otherwise, the garbage collector is called to immediately free the |
|---|
| 814 |
memory allocated for the class instance or struct instance. |
|---|
| 815 |
If the garbage collector was not used to allocate the memory for |
|---|
| 816 |
the instance, undefined behavior will result. |
|---|
| 817 |
) |
|---|
| 818 |
|
|---|
| 819 |
$(P If the $(I UnaryExpression) is a pointer or a dynamic array, |
|---|
| 820 |
the garbage collector is called to immediately release the |
|---|
| 821 |
memory. |
|---|
| 822 |
If the garbage collector was not used to allocate the memory for |
|---|
| 823 |
the instance, undefined behavior will result. |
|---|
| 824 |
) |
|---|
| 825 |
|
|---|
| 826 |
$(P The pointer, dynamic array, or reference is set to $(B null) |
|---|
| 827 |
after the delete is performed. |
|---|
| 828 |
) |
|---|
| 829 |
|
|---|
| 830 |
$(P If $(I UnaryExpression) is a variable allocated |
|---|
| 831 |
on the stack, the class destructor (if any) is called for that |
|---|
| 832 |
instance. Neither the garbage collector nor any class deallocator |
|---|
| 833 |
is called. |
|---|
| 834 |
) |
|---|
| 835 |
|
|---|
| 836 |
<h3>Cast Expressions</h3> |
|---|
| 837 |
|
|---|
| 838 |
$(GRAMMAR |
|---|
| 839 |
$(GNAME CastExpression): |
|---|
| 840 |
$(B cast $(LPAREN)) $(LINK2 declaration.html#Type, $(I Type)) $(B $(RPAREN)) $(GLINK UnaryExpression) |
|---|
| 841 |
$(B cast $(LPAREN)) $(I CastParam) $(B $(RPAREN)) $(GLINK UnaryExpression) |
|---|
| 842 |
|
|---|
| 843 |
$(GNAME CastParam): |
|---|
| 844 |
$(LINK2 declaration.html#Type, $(I Type)) |
|---|
| 845 |
$(B const) |
|---|
| 846 |
$(B const shared) |
|---|
| 847 |
$(B shared const) |
|---|
| 848 |
$(B inout) |
|---|
| 849 |
$(B inout shared) |
|---|
| 850 |
$(B shared inout) |
|---|
| 851 |
$(B immutable) |
|---|
| 852 |
$(B shared) |
|---|
| 853 |
) |
|---|
| 854 |
|
|---|
| 855 |
$(P A $(I CastExpression) converts the $(I UnaryExpression) |
|---|
| 856 |
to $(LINK2 declaration.html#Type, $(I Type)). |
|---|
| 857 |
) |
|---|
| 858 |
|
|---|
| 859 |
------------- |
|---|
| 860 |
$(B cast)(foo) -p; // cast (-p) to type foo |
|---|
| 861 |
(foo) - p; // subtract p from foo |
|---|
| 862 |
------------- |
|---|
| 863 |
|
|---|
| 864 |
$(P Any casting of a class reference to a |
|---|
| 865 |
derived class reference is done with a runtime check to make sure it |
|---|
| 866 |
really is a downcast. $(B null) is the result if it isn't. |
|---|
| 867 |
$(B Note:) This is equivalent to the behavior of the |
|---|
| 868 |
dynamic_cast operator in C++. |
|---|
| 869 |
) |
|---|
| 870 |
|
|---|
| 871 |
------------- |
|---|
| 872 |
class A { ... } |
|---|
| 873 |
class B : A { ... } |
|---|
| 874 |
|
|---|
| 875 |
void test(A a, B b) |
|---|
| 876 |
{ |
|---|
| 877 |
B bx = a; // error, need cast |
|---|
| 878 |
B bx = cast(B) a; // bx is null if a is not a B |
|---|
| 879 |
A ax = b; // no cast needed |
|---|
| 880 |
A ax = cast(A) b; // no runtime check needed for upcast |
|---|
| 881 |
} |
|---|
| 882 |
------------- |
|---|
| 883 |
|
|---|
| 884 |
$(P In order to determine if an object $(TT o) is an instance of |
|---|
| 885 |
a class $(TT B) use a cast: |
|---|
| 886 |
) |
|---|
| 887 |
|
|---|
| 888 |
------------- |
|---|
| 889 |
if ($(B cast)(B) o) |
|---|
| 890 |
{ |
|---|
| 891 |
// o is an instance of B |
|---|
| 892 |
} |
|---|
| 893 |
else |
|---|
| 894 |
{ |
|---|
| 895 |
// o is not an instance of B |
|---|
| 896 |
} |
|---|
| 897 |
------------- |
|---|
| 898 |
|
|---|
| 899 |
$(P Casting a floating point literal from one type to another |
|---|
| 900 |
changes its type, but internally it is retained at full |
|---|
| 901 |
precision for the purposes of constant folding. |
|---|
| 902 |
) |
|---|
| 903 |
|
|---|
| 904 |
--- |
|---|
| 905 |
void test() |
|---|
| 906 |
{ |
|---|
| 907 |
real a = 3.40483L; |
|---|
| 908 |
real b; |
|---|
| 909 |
b = 3.40483; // literal is not truncated to double precision |
|---|
| 910 |
assert(a == b); |
|---|
| 911 |
assert(a == 3.40483); |
|---|
| 912 |
assert(a == 3.40483L); |
|---|
| 913 |
assert(a == 3.40483F); |
|---|
| 914 |
double d = 3.40483; // truncate literal when assigned to variable |
|---|
| 915 |
assert(d != a); // so it is no longer the same |
|---|
| 916 |
const double x = 3.40483; // assignment to const is not |
|---|
| 917 |
assert(x == a); // truncated if the initializer is visible |
|---|
| 918 |
} |
|---|
| 919 |
--- |
|---|
| 920 |
|
|---|
| 921 |
$(P Casting a value $(I v) to a struct $(I S), when value is not a struct |
|---|
| 922 |
of the same type, is equivalent to: |
|---|
| 923 |
) |
|---|
| 924 |
|
|---|
| 925 |
--- |
|---|
| 926 |
S(v) |
|---|
| 927 |
--- |
|---|
| 928 |
|
|---|
| 929 |
$(V2 |
|---|
| 930 |
<h2><a name="PowExpression">Pow Expressions</a></h2> |
|---|
| 931 |
|
|---|
| 932 |
$(GRAMMAR |
|---|
| 933 |
$(GNAME PowExpression): |
|---|
| 934 |
$(GLINK PostfixExpression) |
|---|
| 935 |
$(GLINK PostfixExpression) ^^ $(GLINK UnaryExpression) |
|---|
| 936 |
) |
|---|
| 937 |
|
|---|
| 938 |
$(P $(I PowExpression) raises its left operand to the power of its |
|---|
| 939 |
right operand. |
|---|
| 940 |
) |
|---|
| 941 |
) |
|---|
| 942 |
|
|---|
| 943 |
|
|---|
| 944 |
<h2>Postfix Expressions</h2> |
|---|
| 945 |
|
|---|
| 946 |
$(GRAMMAR |
|---|
| 947 |
$(GNAME PostfixExpression): |
|---|
| 948 |
$(GLINK PrimaryExpression) |
|---|
| 949 |
$(I PostfixExpression) $(B .) $(I Identifier) |
|---|
| 950 |
$(I PostfixExpression) $(B .) $(GLINK2 template, TemplateInstance) |
|---|
| 951 |
$(I PostfixExpression) $(B .) $(GLINK NewExpression) |
|---|
| 952 |
$(I PostfixExpression) $(B ++) |
|---|
| 953 |
$(I PostfixExpression) $(B --) |
|---|
| 954 |
$(I PostfixExpression) $(B ( )) |
|---|
| 955 |
$(I PostfixExpression) $(B $(LPAREN)) $(GLINK ArgumentList) $(B $(RPAREN)) |
|---|
| 956 |
$(GLINK IndexExpression) |
|---|
| 957 |
$(GLINK SliceExpression) |
|---|
| 958 |
) |
|---|
| 959 |
|
|---|
| 960 |
<h2>Index Expressions</h2> |
|---|
| 961 |
|
|---|
| 962 |
$(GRAMMAR |
|---|
| 963 |
$(GNAME IndexExpression): |
|---|
| 964 |
$(GLINK PostfixExpression) $(B [) $(GLINK ArgumentList) $(B ]) |
|---|
| 965 |
) |
|---|
| 966 |
|
|---|
| 967 |
$(P $(I PostfixExpression) is evaluated. |
|---|
| 968 |
|
|---|
| 969 |
If $(I PostfixExpression) is an expression of type |
|---|
| 970 |
static array or dynamic array, the symbol $(DOLLAR) is |
|---|
| 971 |
set to be the the number of elements in the array. |
|---|
| 972 |
|
|---|
| 973 |
If $(I PostfixExpression) is an $(I ExpressionTuple), |
|---|
| 974 |
the symbol $(DOLLAR) is |
|---|
| 975 |
set to be the the number of elements in the tuple. |
|---|
| 976 |
|
|---|
| 977 |
A new declaration scope is created for the evaluation of the |
|---|
| 978 |
$(GLINK ArgumentList) and $(DOLLAR) appears in that scope only. |
|---|
| 979 |
) |
|---|
| 980 |
|
|---|
| 981 |
$(P If $(I PostfixExpression) is an $(I ExpressionTuple), |
|---|
| 982 |
then the $(GLINK ArgumentList) must consist of only one argument, |
|---|
| 983 |
and that must be statically evaluatable to an integral constant. |
|---|
| 984 |
That integral constant $(I n) then selects the $(I n)th |
|---|
| 985 |
expression in the $(I ExpressionTuple), which is the result |
|---|
| 986 |
of the $(I IndexExpression). |
|---|
| 987 |
It is an error if $(I n) is out of bounds of the $(I ExpressionTuple). |
|---|
| 988 |
) |
|---|
| 989 |
|
|---|
| 990 |
<h2>Slice Expressions</h2> |
|---|
| 991 |
|
|---|
| 992 |
$(GRAMMAR |
|---|
| 993 |
$(GNAME SliceExpression): |
|---|
| 994 |
$(GLINK PostfixExpression) $(B [ ]) |
|---|
| 995 |
$(GLINK PostfixExpression) $(B [) $(GLINK AssignExpression) $(B ..) $(GLINK AssignExpression) $(B ]) |
|---|
| 996 |
) |
|---|
| 997 |
|
|---|
| 998 |
$(P $(I PostfixExpression) is evaluated. |
|---|
| 999 |
if $(I PostfixExpression) is an expression of type |
|---|
| 1000 |
static array or dynamic array, the variable $(B length) |
|---|
| 1001 |
(and the special variable $(DOLLAR)) |
|---|
| 1002 |
is declared and set to be the length of the array. |
|---|
| 1003 |
A new declaration scope is created for the evaluation of the |
|---|
| 1004 |
$(GLINK AssignExpression)..$(GLINK AssignExpression) |
|---|
| 1005 |
and $(B length) (and $(DOLLAR)) appears in that scope only. |
|---|
| 1006 |
) |
|---|
| 1007 |
|
|---|
| 1008 |
$(P The first $(I AssignExpression) is taken to be the inclusive |
|---|
| 1009 |
lower bound |
|---|
| 1010 |
of the slice, and the second $(I AssignExpression) is the |
|---|
| 1011 |
exclusive upper bound. |
|---|
| 1012 |
The result of the expression is a slice of the $(I PostfixExpression) |
|---|
| 1013 |
array. |
|---|
| 1014 |
) |
|---|
| 1015 |
|
|---|
| 1016 |
$(P If the $(B [ ]) form is used, the slice is of the entire |
|---|
| 1017 |
array. |
|---|
| 1018 |
) |
|---|
| 1019 |
|
|---|
| 1020 |
$(P The type of the slice is a dynamic array of the element |
|---|
| 1021 |
type of the $(I PostfixExpression). |
|---|
| 1022 |
) |
|---|
| 1023 |
|
|---|
| 1024 |
$(P If $(I PostfixExpression) is an $(I ExpressionTuple), then |
|---|
| 1025 |
the result of the slice is a new $(I ExpressionTuple) formed |
|---|
| 1026 |
from the upper and lower bounds, which must statically evaluate |
|---|
| 1027 |
to integral constants. |
|---|
| 1028 |
It is an error if those |
|---|
| 1029 |
bounds are out of range. |
|---|
| 1030 |
) |
|---|
| 1031 |
|
|---|
| 1032 |
<h2>Primary Expressions</h2> |
|---|
| 1033 |
|
|---|
| 1034 |
$(GRAMMAR |
|---|
| 1035 |
$(GNAME PrimaryExpression): |
|---|
| 1036 |
$(I Identifier) |
|---|
| 1037 |
$(B .)$(I Identifier) |
|---|
| 1038 |
$(LINK2 template.html#TemplateInstance, $(I TemplateInstance)) |
|---|
| 1039 |
$(LINK2 #this, $(B this)) |
|---|
| 1040 |
$(LINK2 #super, $(B super)) |
|---|
| 1041 |
$(LINK2 #null, $(B null)) |
|---|
| 1042 |
$(B true) |
|---|
| 1043 |
$(B false) |
|---|
| 1044 |
$(B $) |
|---|
| 1045 |
$(V2 $(B __FILE__) |
|---|
| 1046 |
$(B __LINE__)) |
|---|
| 1047 |
$(GLINK2 lex, IntegerLiteral) |
|---|
| 1048 |
$(GLINK2 lex, FloatLiteral) |
|---|
| 1049 |
$(GLINK CharacterLiteral) |
|---|
| 1050 |
$(GLINK StringLiterals) |
|---|
| 1051 |
$(GLINK ArrayLiteral) |
|---|
| 1052 |
$(GLINK AssocArrayLiteral) |
|---|
| 1053 |
$(GLINK FunctionLiteral) |
|---|
| 1054 |
$(GLINK AssertExpression) |
|---|
| 1055 |
$(GLINK MixinExpression) |
|---|
| 1056 |
$(GLINK ImportExpression) |
|---|
| 1057 |
$(LINK2 declaration.html#BasicTypeX, $(I BasicType)) $(B .) $(I Identifier) |
|---|
| 1058 |
$(LINK2 declaration.html#Typeof, $(I Typeof)) |
|---|
| 1059 |
$(GLINK TypeidExpression) |
|---|
| 1060 |
$(GLINK IsExpression) |
|---|
| 1061 |
$(B $(LPAREN)) $(I Expression) $(B $(RPAREN)) |
|---|
| 1062 |
$(V2 $(LINK2 traits.html#TraitsExpression, $(I TraitsExpression))) |
|---|
| 1063 |
) |
|---|
| 1064 |
|
|---|
| 1065 |
<h3>.Identifier</h3> |
|---|
| 1066 |
|
|---|
| 1067 |
$(I Identifier) is looked up at module scope, rather than the current |
|---|
| 1068 |
lexically nested scope. |
|---|
| 1069 |
|
|---|
| 1070 |
<h3>$(LNAME2 this, this)</h3> |
|---|
| 1071 |
|
|---|
| 1072 |
$(P Within a non-static member function, $(B this) resolves to |
|---|
| 1073 |
a reference to the object for which the function was called. |
|---|
| 1074 |
If the object is an instance of a struct, $(B this) will |
|---|
| 1075 |
be a pointer to that instance. |
|---|
| 1076 |
If a member function is called with an explicit reference |
|---|
| 1077 |
to $(B typeof(this)), a non-virtual call is made: |
|---|
| 1078 |
) |
|---|
| 1079 |
|
|---|
| 1080 |
------------- |
|---|
| 1081 |
class A |
|---|
| 1082 |
{ |
|---|
| 1083 |
char get() { return 'A'; } |
|---|
| 1084 |
|
|---|
| 1085 |
char foo() { return $(B typeof(this)).get(); } |
|---|
| 1086 |
char bar() { return $(B this).get(); } |
|---|
| 1087 |
} |
|---|
| 1088 |
|
|---|
| 1089 |
class B : A |
|---|
| 1090 |
{ |
|---|
| 1091 |
char get() { return 'B'; } |
|---|
| 1092 |
} |
|---|
| 1093 |
|
|---|
| 1094 |
void main() |
|---|
| 1095 |
{ |
|---|
| 1096 |
B b = new B(); |
|---|
| 1097 |
|
|---|
| 1098 |
b.foo(); // returns 'A' |
|---|
| 1099 |
b.bar(); // returns 'B' |
|---|
| 1100 |
} |
|---|
| 1101 |
------------- |
|---|
| 1102 |
|
|---|
| 1103 |
|
|---|
| 1104 |
<h3>$(LNAME2 super, super)</h3> |
|---|
| 1105 |
|
|---|
| 1106 |
$(P $(B super) is identical to $(B this), except that it is |
|---|
| 1107 |
cast to $(B this)'s base class. |
|---|
| 1108 |
It is an error if there is no base class. |
|---|
| 1109 |
It is an error to use $(B super) within a struct member function. |
|---|
| 1110 |
(Only class $(TT Object) has no base class.) |
|---|
| 1111 |
If a member function is called with an explicit reference |
|---|
| 1112 |
to $(B super), a non-virtual call is made. |
|---|
| 1113 |
) |
|---|
| 1114 |
|
|---|
| 1115 |
<h3>$(LNAME2 null, null)</h3> |
|---|
| 1116 |
|
|---|
| 1117 |
$(P $(B null) represents the null value for |
|---|
| 1118 |
pointers, pointers to functions, delegates, |
|---|
| 1119 |
dynamic arrays, associative arrays, |
|---|
| 1120 |
and class objects. |
|---|
| 1121 |
If it has not already been cast to a type, |
|---|
| 1122 |
it is given the type (void *) and it is an exact conversion |
|---|
| 1123 |
to convert it to the null value for pointers, pointers to |
|---|
| 1124 |
functions, delegates, etc. |
|---|
| 1125 |
After it is cast to a type, such conversions are implicit, |
|---|
| 1126 |
but no longer exact. |
|---|
| 1127 |
) |
|---|
| 1128 |
|
|---|
| 1129 |
<h3>true, false</h3> |
|---|
| 1130 |
|
|---|
| 1131 |
These are of type $(B bool) and when cast to another integral |
|---|
| 1132 |
type become the values 1 and 0, |
|---|
| 1133 |
respectively. |
|---|
| 1134 |
|
|---|
| 1135 |
<h3><a name="CharacterLiteral">Character Literals</a></h3> |
|---|
| 1136 |
|
|---|
| 1137 |
Character literals are single characters and resolve to one |
|---|
| 1138 |
of type $(B char), $(B wchar), or $(B dchar). |
|---|
| 1139 |
If the literal is a \u escape sequence, it resolves to type $(B wchar). |
|---|
| 1140 |
If the literal is a \U escape sequence, it resolves to type $(B dchar). |
|---|
| 1141 |
Otherwise, it resolves to the type with the smallest size it |
|---|
| 1142 |
will fit into. |
|---|
| 1143 |
|
|---|
| 1144 |
<h3>String Literals</h3> |
|---|
| 1145 |
|
|---|
| 1146 |
$(GRAMMAR |
|---|
| 1147 |
$(GNAME StringLiterals): |
|---|
| 1148 |
$(LINK2 lex.html#StringLiteral, $(I StringLiteral)) |
|---|
| 1149 |
$(I StringLiterals) $(LINK2 lex.html#StringLiteral, $(I StringLiteral)) |
|---|
| 1150 |
) |
|---|
| 1151 |
|
|---|
| 1152 |
$(P String literals can implicitly convert to any |
|---|
| 1153 |
of the following types, they have equal weight: |
|---|
| 1154 |
) |
|---|
| 1155 |
|
|---|
| 1156 |
$(V1 |
|---|
| 1157 |
$(TABLE1 |
|---|
| 1158 |
$(TR $(TD char*)) |
|---|
| 1159 |
$(TR $(TD wchar*)) |
|---|
| 1160 |
$(TR $(TD dchar*)) |
|---|
| 1161 |
$(TR $(TD char[])) |
|---|
| 1162 |
$(TR $(TD wchar[])) |
|---|
| 1163 |
$(TR $(TD dchar[])) |
|---|
| 1164 |
) |
|---|
| 1165 |
) |
|---|
| 1166 |
$(V2 |
|---|
| 1167 |
$(TABLE1 |
|---|
| 1168 |
$(TR $(TD immutable(char)*)) |
|---|
| 1169 |
$(TR $(TD immutable(wchar)*)) |
|---|
| 1170 |
$(TR $(TD immutable(dchar)*)) |
|---|
| 1171 |
$(TR $(TD immutable(char)[])) |
|---|
| 1172 |
$(TR $(TD immutable(wchar)[])) |
|---|
| 1173 |
$(TR $(TD immutable(dchar)[])) |
|---|
| 1174 |
) |
|---|
| 1175 |
) |
|---|
| 1176 |
$(P String literals have a 0 appended to them, which makes |
|---|
| 1177 |
them easy to pass to C or C++ functions expecting a $(CODE const char*) |
|---|
| 1178 |
string. |
|---|
| 1179 |
The 0 is not included in the $(CODE .length) property of the |
|---|
| 1180 |
string literal. |
|---|
| 1181 |
) |
|---|
| 1182 |
|
|---|
| 1183 |
<h3>Array Literals</h3> |
|---|
| 1184 |
|
|---|
| 1185 |
$(GRAMMAR |
|---|
| 1186 |
$(GNAME ArrayLiteral): |
|---|
| 1187 |
$(B [) $(GLINK ArgumentList) $(B ]) |
|---|
| 1188 |
) |
|---|
| 1189 |
|
|---|
| 1190 |
$(P Array literals are a comma-separated list of $(GLINK AssignExpression)s |
|---|
| 1191 |
between square brackets [ and ]. |
|---|
| 1192 |
The $(I AssignExpression)s form the elements of a static array, |
|---|
| 1193 |
the length of the array is the number of elements. |
|---|
| 1194 |
The type of the first element is taken to be the type of |
|---|
| 1195 |
all the elements, and all elements are implicitly converted |
|---|
| 1196 |
to that type. |
|---|
| 1197 |
If that type is a static array, it is converted to a dynamic |
|---|
| 1198 |
array. |
|---|
| 1199 |
) |
|---|
| 1200 |
|
|---|
| 1201 |
--- |
|---|
| 1202 |
[1,2,3]; // type is int[3], with elements 1, 2 and 3 |
|---|
| 1203 |
[1u,2,3]; // type is uint[3], with elements 1u, 2u, and 3u |
|---|
| 1204 |
--- |
|---|
| 1205 |
|
|---|
| 1206 |
$(P If any of the arguments in the $(GLINK ArgumentList) are |
|---|
| 1207 |
an $(I ExpressionTuple), then the elements of the $(I ExpressionTuple) |
|---|
| 1208 |
are inserted as arguments in place of the tuple. |
|---|
| 1209 |
) |
|---|
| 1210 |
|
|---|
| 1211 |
$(P Array literals are allocated on the memory managed heap. |
|---|
| 1212 |
Thus, they can be returned safely from functions:) |
|---|
| 1213 |
|
|---|
| 1214 |
--- |
|---|
| 1215 |
int[] foo() |
|---|
| 1216 |
{ |
|---|
| 1217 |
return [1, 2, 3]; |
|---|
| 1218 |
} |
|---|
| 1219 |
--- |
|---|
| 1220 |
|
|---|
| 1221 |
$(P When array literals are cast to another array type, each |
|---|
| 1222 |
element of the array is cast to the new element type. |
|---|
| 1223 |
When arrays that are not literals are cast, the array is |
|---|
| 1224 |
reinterpreted as the new type, and the length is recomputed: |
|---|
| 1225 |
) |
|---|
| 1226 |
|
|---|
| 1227 |
--- |
|---|
| 1228 |
import std.stdio; |
|---|
| 1229 |
|
|---|
| 1230 |
void main() |
|---|
| 1231 |
{ |
|---|
| 1232 |
// cast array literal |
|---|
| 1233 |
const short[] ct = cast(short[]) [cast(byte)1, 1]; |
|---|
| 1234 |
writeln(ct); // writes [1 1] |
|---|
| 1235 |
|
|---|
| 1236 |
// cast other array expression |
|---|
| 1237 |
short[] rt = cast(short[]) [cast(byte)1, 1].dup; |
|---|
| 1238 |
writeln(rt); // writes [257] |
|---|
| 1239 |
} |
|---|
| 1240 |
--- |
|---|
| 1241 |
|
|---|
| 1242 |
|
|---|
| 1243 |
<h3>Associative Array Literals</h3> |
|---|
| 1244 |
|
|---|
| 1245 |
$(GRAMMAR |
|---|
| 1246 |
$(GNAME AssocArrayLiteral): |
|---|
| 1247 |
$(B [) $(I KeyValuePairs) $(B ]) |
|---|
| 1248 |
|
|---|
| 1249 |
$(GNAME KeyValuePairs): |
|---|
| 1250 |
$(I KeyValuePair) |
|---|
| 1251 |
$(I KeyValuePair) $(B ,) $(I KeyValuePairs) |
|---|
| 1252 |
|
|---|
| 1253 |
$(GNAME KeyValuePair): |
|---|
| 1254 |
$(I KeyExpression) $(B :) $(I ValueExpression) |
|---|
| 1255 |
|
|---|
| 1256 |
$(GNAME KeyExpression): |
|---|
| 1257 |
$(GLINK AssignExpression) |
|---|
| 1258 |
|
|---|
| 1259 |
$(GNAME ValueExpression): |
|---|
| 1260 |
$(GLINK AssignExpression) |
|---|
| 1261 |
) |
|---|
| 1262 |
|
|---|
| 1263 |
$(P Associative array literals are a comma-separated list of |
|---|
| 1264 |
$(I key):$(I value) pairs |
|---|
| 1265 |
between square brackets [ and ]. |
|---|
| 1266 |
The list cannot be empty. |
|---|
| 1267 |
The type of the first key is taken to be the type of |
|---|
| 1268 |
all the keys, and all subsequent keys are implicitly converted |
|---|
| 1269 |
to that type. |
|---|
| 1270 |
The type of the first value is taken to be the type of |
|---|
| 1271 |
all the values, and all subsequent values are implicitly converted |
|---|
| 1272 |
to that type. |
|---|
| 1273 |
An $(I AssocArrayLiteral) cannot be used to statically initialize |
|---|
| 1274 |
anything. |
|---|
| 1275 |
) |
|---|
| 1276 |
|
|---|
| 1277 |
--- |
|---|
| 1278 |
[21u:"he",38:"ho",2:"hi"]; // type is char[2][uint], with keys 21u, 38u and 2u |
|---|
| 1279 |
// and values "he", "ho", and "hi" |
|---|
| 1280 |
--- |
|---|
| 1281 |
|
|---|
| 1282 |
$(P If any of the keys or values in the $(I KeyValuePairs) are |
|---|
| 1283 |
an $(I ExpressionTuple), then the elements of the $(I ExpressionTuple) |
|---|
| 1284 |
are inserted as arguments in place of the tuple. |
|---|
| 1285 |
) |
|---|
| 1286 |
|
|---|
| 1287 |
<h3>Function Literals</h3> |
|---|
| 1288 |
|
|---|
| 1289 |
$(GRAMMAR |
|---|
| 1290 |
$(GNAME FunctionLiteral): |
|---|
| 1291 |
$(B function) $(LINK2 declaration.html#Type, $(I Type))$(OPT) $(I ParameterAttributes) $(OPT) $(LINK2 function.html#FunctionBody, $(I FunctionBody)) |
|---|
| 1292 |
$(B delegate) $(LINK2 declaration.html#Type, $(I Type))$(OPT) $(I ParameterAttributes) $(OPT) $(LINK2 function.html#FunctionBody, $(I FunctionBody)) |
|---|
| 1293 |
$(I ParameterAttributes) $(LINK2 function.html#FunctionBody, $(I FunctionBody)) |
|---|
| 1294 |
$(LINK2 function.html#FunctionBody, $(I FunctionBody)) |
|---|
| 1295 |
|
|---|
| 1296 |
$(GNAME ParameterAttributes): |
|---|
| 1297 |
$(LINK2 declaration.html#Parameters, $(I Parameters)) |
|---|
| 1298 |
$(V2 $(LINK2 declaration.html#Parameters, $(I Parameters)) $(LINK2 declaration.html#FunctionAttributes, $(I FunctionAttributes))) |
|---|
| 1299 |
) |
|---|
| 1300 |
|
|---|
| 1301 |
$(I FunctionLiteral)s enable embedding anonymous functions |
|---|
| 1302 |
and anonymous delegates directly into expressions. |
|---|
| 1303 |
$(I Type) is the return type of the function or delegate, |
|---|
| 1304 |
if omitted it is inferred from any $(I ReturnStatement)s |
|---|
| 1305 |
in the $(I FunctionBody). |
|---|
| 1306 |
$(B $(LPAREN)) $(GLINK ArgumentList) $(B $(RPAREN)) |
|---|
| 1307 |
forms the arguments to the function. |
|---|
| 1308 |
If omitted it defaults to the empty argument list $(B ()). |
|---|
| 1309 |
The type of a function literal is pointer to function or |
|---|
| 1310 |
pointer to delegate. |
|---|
| 1311 |
If the keywords $(B function) or $(B delegate) are omitted, |
|---|
| 1312 |
it defaults to being a delegate. |
|---|
| 1313 |
<p> |
|---|
| 1314 |
|
|---|
| 1315 |
For example: |
|---|
| 1316 |
|
|---|
| 1317 |
------------- |
|---|
| 1318 |
int function(char c) fp; // declare pointer to a function |
|---|
| 1319 |
|
|---|
| 1320 |
void test() |
|---|
| 1321 |
{ |
|---|
| 1322 |
static int foo(char c) { return 6; } |
|---|
| 1323 |
|
|---|
| 1324 |
fp = &foo; |
|---|
| 1325 |
} |
|---|
| 1326 |
------------- |
|---|
| 1327 |
|
|---|
| 1328 |
is exactly equivalent to: |
|---|
| 1329 |
|
|---|
| 1330 |
------------- |
|---|
| 1331 |
int function(char c) fp; |
|---|
| 1332 |
|
|---|
| 1333 |
void test() |
|---|
| 1334 |
{ |
|---|
| 1335 |
fp = $(B function int(char c) { return 6;}) ; |
|---|
| 1336 |
} |
|---|
| 1337 |
------------- |
|---|
| 1338 |
|
|---|
| 1339 |
And: |
|---|
| 1340 |
|
|---|
| 1341 |
------------- |
|---|
| 1342 |
int abc(int delegate(long i)); |
|---|
| 1343 |
|
|---|
| 1344 |
void test() |
|---|
| 1345 |
{ int b = 3; |
|---|
| 1346 |
int foo(long c) { return 6 + b; } |
|---|
| 1347 |
|
|---|
| 1348 |
abc(&foo); |
|---|
| 1349 |
} |
|---|
| 1350 |
------------- |
|---|
| 1351 |
|
|---|
| 1352 |
is exactly equivalent to: |
|---|
| 1353 |
|
|---|
| 1354 |
------------- |
|---|
| 1355 |
int abc(int delegate(long i)); |
|---|
| 1356 |
|
|---|
| 1357 |
void test() |
|---|
| 1358 |
{ int b = 3; |
|---|
| 1359 |
|
|---|
| 1360 |
abc( $(B delegate int(long c) { return 6 + b; }) ); |
|---|
| 1361 |
} |
|---|
| 1362 |
------------- |
|---|
| 1363 |
|
|---|
| 1364 |
$(P and the following where the return type $(B int) is |
|---|
| 1365 |
inferred:) |
|---|
| 1366 |
|
|---|
| 1367 |
------------- |
|---|
| 1368 |
int abc(int delegate(long i)); |
|---|
| 1369 |
|
|---|
| 1370 |
void test() |
|---|
| 1371 |
{ int b = 3; |
|---|
| 1372 |
|
|---|
| 1373 |
abc( $(B (long c) { return 6 + b; }) ); |
|---|
| 1374 |
} |
|---|
| 1375 |
------------- |
|---|
| 1376 |
|
|---|
| 1377 |
Anonymous delegates can behave like arbitrary statement literals. |
|---|
| 1378 |
For example, here an arbitrary statement is executed by a loop: |
|---|
| 1379 |
|
|---|
| 1380 |
------------- |
|---|
| 1381 |
double test() |
|---|
| 1382 |
{ double d = 7.6; |
|---|
| 1383 |
float f = 2.3; |
|---|
| 1384 |
|
|---|
| 1385 |
void loop(int k, int j, void delegate() statement) |
|---|
| 1386 |
{ |
|---|
| 1387 |
for (int i = k; i < j; i++) |
|---|
| 1388 |
{ |
|---|
| 1389 |
statement(); |
|---|
| 1390 |
} |
|---|
| 1391 |
} |
|---|
| 1392 |
|
|---|
| 1393 |
loop(5, 100, $(B { d += 1; }) ); |
|---|
| 1394 |
loop(3, 10, $(B { f += 3; }) ); |
|---|
| 1395 |
|
|---|
| 1396 |
return d + f; |
|---|
| 1397 |
} |
|---|
| 1398 |
------------- |
|---|
| 1399 |
|
|---|
| 1400 |
When comparing with <a href="function.html#nested">nested |
|---|
| 1401 |
functions</a>, the $(B function) form is analogous to static |
|---|
| 1402 |
or non-nested functions, and the $(B delegate) form is |
|---|
| 1403 |
analogous to non-static nested functions. In other words, |
|---|
| 1404 |
a delegate literal can access stack variables in its enclosing |
|---|
| 1405 |
function, a function literal cannot. |
|---|
| 1406 |
|
|---|
| 1407 |
|
|---|
| 1408 |
<h3>Assert Expressions</h3> |
|---|
| 1409 |
|
|---|
| 1410 |
$(GRAMMAR |
|---|
| 1411 |
$(GNAME AssertExpression): |
|---|
| 1412 |
$(B assert $(LPAREN)) $(GLINK AssignExpression) $(B $(RPAREN)) |
|---|
| 1413 |
$(B assert $(LPAREN)) $(GLINK AssignExpression) $(B ,) $(GLINK AssignExpression) $(B $(RPAREN)) |
|---|
| 1414 |
) |
|---|
| 1415 |
|
|---|
| 1416 |
$(P Asserts evaluate the $(I expression). If the result is false, |
|---|
| 1417 |
an $(B AssertError) is thrown. If the result is true, then no |
|---|
| 1418 |
exception is thrown. |
|---|
| 1419 |
It is an error if the $(I expression) contains any side effects |
|---|
| 1420 |
that the program depends on. The compiler may optionally not |
|---|
| 1421 |
evaluate assert expressions at all. |
|---|
| 1422 |
The result type of an assert expression is $(TT void). |
|---|
| 1423 |
Asserts are a fundamental part of the |
|---|
| 1424 |
<a href="dbc.html">Contract Programming</a> |
|---|
| 1425 |
support in D. |
|---|
| 1426 |
) |
|---|
| 1427 |
|
|---|
| 1428 |
$(P The expression $(TT assert(0)) is a special case; it |
|---|
| 1429 |
signifies that it is unreachable code. |
|---|
| 1430 |
Either $(B AssertError) is thrown at runtime if it is reachable, |
|---|
| 1431 |
or the execution is halted |
|---|
| 1432 |
(on the x86 processor, a $(B HLT) instruction can be used to halt |
|---|
| 1433 |
execution). |
|---|
| 1434 |
The optimization and code generation phases of compilation may |
|---|
| 1435 |
assume that it is unreachable code. |
|---|
| 1436 |
) |
|---|
| 1437 |
|
|---|
| 1438 |
$(P The second $(I Expression), if present, must be implicitly |
|---|
| 1439 |
convertible to type $(V1 $(TT char[]))$(V2 $(TT const(char)[])). |
|---|
| 1440 |
It is evaluated if the |
|---|
| 1441 |
result is false, and the string result is appended to the |
|---|
| 1442 |
$(B AssertError)'s message. |
|---|
| 1443 |
) |
|---|
| 1444 |
|
|---|
| 1445 |
---- |
|---|
| 1446 |
void main() |
|---|
| 1447 |
{ |
|---|
| 1448 |
assert(0, "an" ~ " error message"); |
|---|
| 1449 |
} |
|---|
| 1450 |
---- |
|---|
| 1451 |
|
|---|
| 1452 |
$(P When compiled and run, it will produce the message:) |
|---|
| 1453 |
|
|---|
| 1454 |
$(CONSOLE |
|---|
| 1455 |
Error: AssertError Failure test.d(3) an error message |
|---|
| 1456 |
) |
|---|
| 1457 |
|
|---|
| 1458 |
|
|---|
| 1459 |
<h3><a name="MixinExpression">Mixin Expressions</a></h3> |
|---|
| 1460 |
|
|---|
| 1461 |
$(GRAMMAR |
|---|
| 1462 |
$(GNAME MixinExpression): |
|---|
| 1463 |
$(B mixin $(LPAREN)) $(GLINK AssignExpression) $(B $(RPAREN)) |
|---|
| 1464 |
) |
|---|
| 1465 |
|
|---|
| 1466 |
$(P The $(I AssignExpression) must evaluate at compile time |
|---|
| 1467 |
to a constant string. |
|---|
| 1468 |
The text contents of the string must be compilable as a valid |
|---|
| 1469 |
$(I AssignExpression), and is compiled as such. |
|---|
| 1470 |
) |
|---|
| 1471 |
|
|---|
| 1472 |
--- |
|---|
| 1473 |
int foo(int x) |
|---|
| 1474 |
{ |
|---|
| 1475 |
return mixin("x + 1") * 7; // same as ((x + 1) * 7) |
|---|
| 1476 |
} |
|---|
| 1477 |
--- |
|---|
| 1478 |
|
|---|
| 1479 |
<h3><a name="ImportExpression">Import Expressions</a></h3> |
|---|
| 1480 |
|
|---|
| 1481 |
$(GRAMMAR |
|---|
| 1482 |
$(GNAME ImportExpression): |
|---|
| 1483 |
$(B import $(LPAREN)) $(GLINK AssignExpression) $(B $(RPAREN)) |
|---|
| 1484 |
) |
|---|
| 1485 |
|
|---|
| 1486 |
$(P The $(I AssignExpression) must evaluate at compile time |
|---|
| 1487 |
to a constant string. |
|---|
| 1488 |
The text contents of the string are interpreted as a file |
|---|
| 1489 |
name. The file is read, and the exact contents of the file |
|---|
| 1490 |
become a string literal. |
|---|
| 1491 |
) |
|---|
| 1492 |
|
|---|
| 1493 |
$(P Implementations may restrict the file name in order to avoid |
|---|
| 1494 |
directory traversal security vulnerabilities. |
|---|
| 1495 |
A possible restriction might be to disallow any path components |
|---|
| 1496 |
in the file name. |
|---|
| 1497 |
) |
|---|
| 1498 |
|
|---|
| 1499 |
--- |
|---|
| 1500 |
void foo() |
|---|
| 1501 |
{ |
|---|
| 1502 |
// Prints contents of file foo.txt |
|---|
| 1503 |
writefln( import("foo.txt") ); |
|---|
| 1504 |
} |
|---|
| 1505 |
--- |
|---|
| 1506 |
|
|---|
| 1507 |
<h3><a name="typeidexpression">Typeid Expressions</a></h3> |
|---|
| 1508 |
|
|---|
| 1509 |
$(GRAMMAR |
|---|
| 1510 |
$(GNAME TypeidExpression): |
|---|
| 1511 |
$(B typeid $(LPAREN)) $(LINK2 declaration.html#Type, $(I Type)) $(B $(RPAREN)) |
|---|
| 1512 |
$(V2 $(B typeid $(LPAREN)) $(GLINK Expression) $(B $(RPAREN))) |
|---|
| 1513 |
) |
|---|
| 1514 |
|
|---|
| 1515 |
$(V1 |
|---|
| 1516 |
$(P Returns an instance of class |
|---|
| 1517 |
$(LINK2 phobos/object.html, $(B TypeInfo)) |
|---|
| 1518 |
corresponding |
|---|
| 1519 |
to $(I Type). |
|---|
| 1520 |
) |
|---|
| 1521 |
) |
|---|
| 1522 |
$(V2 |
|---|
| 1523 |
$(P If $(I Type), returns an instance of class |
|---|
| 1524 |
$(LINK2 phobos/object.html, $(B TypeInfo)) |
|---|
| 1525 |
corresponding |
|---|
| 1526 |
to $(I Type). |
|---|
| 1527 |
) |
|---|
| 1528 |
|
|---|
| 1529 |
$(P If $(I Expression), returns an instance of class |
|---|
| 1530 |
$(LINK2 phobos/object.html, $(B TypeInfo)) |
|---|
| 1531 |
corresponding |
|---|
| 1532 |
to the type of the $(I Expression). |
|---|
| 1533 |
If the type is a class, it returns the $(B TypeInfo) |
|---|
| 1534 |
of the dynamic type (i.e. the most derived type). |
|---|
| 1535 |
The $(I Expression) is always executed. |
|---|
| 1536 |
) |
|---|
| 1537 |
|
|---|
| 1538 |
--- |
|---|
| 1539 |
class A { } |
|---|
| 1540 |
class B : A { } |
|---|
| 1541 |
|
|---|
| 1542 |
void main() |
|---|
| 1543 |
{ |
|---|
| 1544 |
writeln(typeid(int)); // int |
|---|
| 1545 |
uint i; |
|---|
| 1546 |
writeln(typeid(i++)); // uint |
|---|
| 1547 |
writeln(i); // 1 |
|---|
| 1548 |
A a = new B(); |
|---|
| 1549 |
writeln(typeid(a)); // B |
|---|
| 1550 |
writeln(typeid(typeof(a))); // A |
|---|
| 1551 |
} |
|---|
| 1552 |
--- |
|---|
| 1553 |
) |
|---|
| 1554 |
|
|---|
| 1555 |
<h3><a name="IsExpression">IsExpression</a></h3> |
|---|
| 1556 |
|
|---|
| 1557 |
$(GRAMMAR |
|---|
| 1558 |
$(GNAME IsExpression): |
|---|
| 1559 |
$(B is $(LPAREN)) $(LINK2 declaration.html#Type, $(I Type)) $(B $(RPAREN)) |
|---|
| 1560 |
$(B is $(LPAREN)) $(LINK2 declaration.html#Type, $(I Type)) $(B :) $(I TypeSpecialization) $(B $(RPAREN)) |
|---|
| 1561 |
$(B is $(LPAREN)) $(LINK2 declaration.html#Type, $(I Type)) $(B ==) $(I TypeSpecialization) $(B $(RPAREN)) |
|---|
| 1562 |
$(B is $(LPAREN)) $(LINK2 declaration.html#Type, $(I Type)) $(I Identifier) $(B $(RPAREN)) |
|---|
| 1563 |
$(B is $(LPAREN)) $(LINK2 declaration.html#Type, $(I Type)) $(I Identifier) $(B :) $(I TypeSpecialization) $(B $(RPAREN)) |
|---|
| 1564 |
$(B is $(LPAREN)) $(LINK2 declaration.html#Type, $(I Type)) $(I Identifier) $(B ==) $(I TypeSpecialization) $(B $(RPAREN)) |
|---|
| 1565 |
$(V2 $(B is $(LPAREN)) $(LINK2 declaration.html#Type, $(I Type)) $(I Identifier) $(B :) $(I TypeSpecialization) $(B ,) $(I TemplateParameterList) $(B $(RPAREN)) |
|---|
| 1566 |
$(B is $(LPAREN)) $(LINK2 declaration.html#Type, $(I Type)) $(I Identifier) $(B ==) $(I TypeSpecialization) $(B ,) $(I TemplateParameterList) $(B $(RPAREN)) |
|---|
| 1567 |
) |
|---|
| 1568 |
|
|---|
| 1569 |
$(GNAME TypeSpecialization): |
|---|
| 1570 |
$(LINK2 declaration.html#Type, $(I Type)) |
|---|
| 1571 |
$(V1 $(B typedef) |
|---|
| 1572 |
) $(B struct) |
|---|
| 1573 |
$(B union) |
|---|
| 1574 |
$(B class) |
|---|
| 1575 |
$(B interface) |
|---|
| 1576 |
$(B enum) |
|---|
| 1577 |
$(B function) |
|---|
| 1578 |
$(B delegate) |
|---|
| 1579 |
$(B super) |
|---|
| 1580 |
$(V2 $(B const) |
|---|
| 1581 |
$(B immutable) |
|---|
| 1582 |
$(B inout) |
|---|
| 1583 |
$(B shared) |
|---|
| 1584 |
$(B return) |
|---|
| 1585 |
)) |
|---|
| 1586 |
|
|---|
| 1587 |
$(I IsExpression)s are evaluated at compile time and are |
|---|
| 1588 |
used for checking for valid types, comparing types for equivalence, |
|---|
| 1589 |
determining if one type can be implicitly converted to another, |
|---|
| 1590 |
and deducing the subtypes of a type. |
|---|
| 1591 |
The result of an $(I IsExpression) is an int of type 0 |
|---|
| 1592 |
if the condition is not satisified, 1 if it is. |
|---|
| 1593 |
<p> |
|---|
| 1594 |
|
|---|
| 1595 |
$(I Type) is the type being tested. It must be syntactically |
|---|
| 1596 |
correct, but it need not be semantically correct. |
|---|
| 1597 |
If it is not semantically correct, the condition is not satisfied. |
|---|
| 1598 |
<p> |
|---|
| 1599 |
|
|---|
| 1600 |
$(I Identifier) is declared to be an alias of the resulting |
|---|
| 1601 |
type if the condition is satisfied. The $(I Identifier) forms |
|---|
| 1602 |
can only be used if the $(I IsExpression) appears in a |
|---|
| 1603 |
<a href="version.html#staticif">$(I StaticIfCondition)</a>. |
|---|
| 1604 |
<p> |
|---|
| 1605 |
|
|---|
| 1606 |
$(I TypeSpecialization) is the type that $(I Type) is being |
|---|
| 1607 |
compared against. |
|---|
| 1608 |
<p> |
|---|
| 1609 |
|
|---|
| 1610 |
The forms of the $(I IsExpression) are: |
|---|
| 1611 |
|
|---|
| 1612 |
$(OL |
|---|
| 1613 |
|
|---|
| 1614 |
$(LI $(B is $(LPAREN)) $(I Type) $(B $(RPAREN))$(BR) |
|---|
| 1615 |
The condition is satisfied if $(I Type) is semantically |
|---|
| 1616 |
correct (it must be syntactically correct regardless). |
|---|
| 1617 |
|
|---|
| 1618 |
------------- |
|---|
| 1619 |
alias int func(int); // func is a alias to a function type |
|---|
| 1620 |
void foo() |
|---|
| 1621 |
{ |
|---|
| 1622 |
if ( $(B is)(func[]) ) // not satisfied because arrays of |
|---|
| 1623 |
// functions are not allowed |
|---|
| 1624 |
writefln("satisfied"); |
|---|
| 1625 |
else |
|---|
| 1626 |
writefln("not satisfied"); |
|---|
| 1627 |
|
|---|
| 1628 |
if ($(B is)([][])) // error, [][] is not a syntactically valid type |
|---|
| 1629 |
... |
|---|
| 1630 |
} |
|---|
| 1631 |
------------- |
|---|
| 1632 |
) |
|---|
| 1633 |
|
|---|
| 1634 |
$(LI $(B is $(LPAREN)) $(I Type) $(B :) $(I TypeSpecialization) $(B $(RPAREN))<br> |
|---|
| 1635 |
The condition is satisfied if $(I Type) is semantically |
|---|
| 1636 |
correct and it is the same as |
|---|
| 1637 |
or can be implicitly converted to $(I TypeSpecialization). |
|---|
| 1638 |
$(I TypeSpecialization) is only allowed to be a $(I Type). |
|---|
| 1639 |
|
|---|
| 1640 |
------------- |
|---|
| 1641 |
alias short bar; |
|---|
| 1642 |
void foo(bar x) |
|---|
| 1643 |
{ |
|---|
| 1644 |
if ( $(B is)(bar : int) ) // satisfied because short can be |
|---|
| 1645 |
// implicitly converted to int |
|---|
| 1646 |
writefln("satisfied"); |
|---|
| 1647 |
else |
|---|
| 1648 |
writefln("not satisfied"); |
|---|
| 1649 |
} |
|---|
| 1650 |
------------- |
|---|
| 1651 |
) |
|---|
| 1652 |
|
|---|
| 1653 |
$(LI $(B is $(LPAREN)) $(I Type) $(B ==) $(I TypeSpecialization) $(B $(RPAREN))<br> |
|---|
| 1654 |
The condition is satisfied if $(I Type) is semantically |
|---|
| 1655 |
correct and is the same type as $(I TypeSpecialization). |
|---|
| 1656 |
<p> |
|---|
| 1657 |
|
|---|
| 1658 |
If $(I TypeSpecialization) is one of |
|---|
| 1659 |
$(V1 $(B typedef) |
|---|
| 1660 |
) $(B struct) |
|---|
| 1661 |
$(B union) |
|---|
| 1662 |
$(B class) |
|---|
| 1663 |
$(B interface) |
|---|
| 1664 |
$(B enum) |
|---|
| 1665 |
$(B function) |
|---|
| 1666 |
$(B delegate) |
|---|
| 1667 |
$(V2 $(B const) |
|---|
| 1668 |
$(B immutable) |
|---|
| 1669 |
$(B shared) |
|---|
| 1670 |
) |
|---|
| 1671 |
then the condition is satisifed if $(I Type) is one of those. |
|---|
| 1672 |
|
|---|
| 1673 |
------------- |
|---|
| 1674 |
alias short bar; |
|---|
| 1675 |
$(V1 typedef char foo;) |
|---|
| 1676 |
void test(bar x) |
|---|
| 1677 |
{ |
|---|
| 1678 |
if ( $(B is)(bar == int) ) // not satisfied because short is not |
|---|
| 1679 |
// the same type as int |
|---|
| 1680 |
writefln("satisfied"); |
|---|
| 1681 |
else |
|---|
| 1682 |
writefln("not satisfied"); |
|---|
| 1683 |
$(V1 |
|---|
| 1684 |
if ( $(B is)(foo == typedef) ) // satisfied because foo is a typedef |
|---|
| 1685 |
writefln("satisfied"); |
|---|
| 1686 |
else |
|---|
| 1687 |
writefln("not satisfied"); |
|---|
| 1688 |
)} |
|---|
| 1689 |
------------- |
|---|
| 1690 |
) |
|---|
| 1691 |
|
|---|
| 1692 |
$(LI $(B is $(LPAREN)) $(I Type) $(I Identifier) $(B $(RPAREN))<br> |
|---|
| 1693 |
The condition is satisfied if $(I Type) is semantically |
|---|
| 1694 |
correct. If so, $(I Identifier) |
|---|
| 1695 |
is declared to be an alias of $(I Type). |
|---|
| 1696 |
|
|---|
| 1697 |
------------- |
|---|
| 1698 |
alias short bar; |
|---|
| 1699 |
void foo(bar x) |
|---|
| 1700 |
{ |
|---|
| 1701 |
static if ( $(B is)(bar T) ) |
|---|
| 1702 |
alias T S; |
|---|
| 1703 |
else |
|---|
| 1704 |
alias long S; |
|---|
| 1705 |
writefln(typeid(S)); // prints "short" |
|---|
| 1706 |
|
|---|
| 1707 |
if ( $(B is)(bar T) ) // error, $(I Identifier) T form can |
|---|
| 1708 |
// only be in $(LINK2 version.html#staticif, $(I StaticIfCondition))s |
|---|
| 1709 |
... |
|---|
| 1710 |
} |
|---|
| 1711 |
------------- |
|---|
| 1712 |
) |
|---|
| 1713 |
|
|---|
| 1714 |
$(LI $(B is $(LPAREN)) $(I Type) $(I Identifier) $(B :) $(I TypeSpecialization) $(B $(RPAREN))<br> |
|---|
| 1715 |
|
|---|
| 1716 |
$(P |
|---|
| 1717 |
The condition is satisfied if $(I Type) is the same as |
|---|
| 1718 |
$(I TypeSpecialization), or if $(I Type) is a class and |
|---|
| 1719 |
$(I TypeSpecialization) is a base class or base interface |
|---|
| 1720 |
of it. |
|---|
| 1721 |
The $(I Identifier) is declared to be either an alias of the |
|---|
| 1722 |
$(I TypeSpecialization) or, if $(I TypeSpecialization) is |
|---|
| 1723 |
dependent on $(I Identifier), the deduced type. |
|---|
| 1724 |
) |
|---|
| 1725 |
|
|---|
| 1726 |
------------- |
|---|
| 1727 |
alias int bar; |
|---|
| 1728 |
alias long* abc; |
|---|
| 1729 |
void foo(bar x, abc a) |
|---|
| 1730 |
{ |
|---|
| 1731 |
static if ( $(B is)(bar T : int) ) |
|---|
| 1732 |
alias T S; |
|---|
| 1733 |
else |
|---|
| 1734 |
alias long S; |
|---|
| 1735 |
|
|---|
| 1736 |
writefln(typeid(S)); // prints "int" |
|---|
| 1737 |
|
|---|
| 1738 |
static if ( $(B is)(abc U : U*) ) |
|---|
| 1739 |
U u; |
|---|
| 1740 |
|
|---|
| 1741 |
writefln(typeid(typeof(u))); // prints "long" |
|---|
| 1742 |
} |
|---|
| 1743 |
------------- |
|---|
| 1744 |
|
|---|
| 1745 |
$(P The way the type of $(I Identifier) is determined is analogous |
|---|
| 1746 |
to the way template parameter types are determined by |
|---|
| 1747 |
$(I TemplateTypeParameterSpecialization). |
|---|
| 1748 |
) |
|---|
| 1749 |
) |
|---|
| 1750 |
|
|---|
| 1751 |
$(LI $(B is $(LPAREN)) $(I Type) $(I Identifier) $(B ==) $(I TypeSpecialization) $(B $(RPAREN))<br> |
|---|
| 1752 |
|
|---|
| 1753 |
|
|---|
| 1754 |
$(P The condition is satisfied if $(I Type) is semantically |
|---|
| 1755 |
correct and is the same as $(I TypeSpecialization). |
|---|
| 1756 |
The $(I Identifier) is declared to be either an alias of the |
|---|
| 1757 |
$(I TypeSpecialization) or, if $(I TypeSpecialization) is |
|---|
| 1758 |
dependent on $(I Identifier), the deduced type. |
|---|
| 1759 |
) |
|---|
| 1760 |
|
|---|
| 1761 |
$(P If $(I TypeSpecialization) is one of |
|---|
| 1762 |
$(V1 $(B typedef) |
|---|
| 1763 |
) $(B struct) |
|---|
| 1764 |
$(B union) |
|---|
| 1765 |
$(B class) |
|---|
| 1766 |
$(B interface) |
|---|
| 1767 |
$(B enum) |
|---|
| 1768 |
$(B function) |
|---|
| 1769 |
$(B delegate) |
|---|
| 1770 |
$(V2 $(B const) |
|---|
| 1771 |
$(B immutable) |
|---|
| 1772 |
$(B shared) |
|---|
| 1773 |
) |
|---|
| 1774 |
then the condition is satisifed if $(I Type) is one of those. |
|---|
| 1775 |
Furthermore, $(I Identifier) is set to be an alias of the type: |
|---|
| 1776 |
) |
|---|
| 1777 |
|
|---|
| 1778 |
$(TABLE1 |
|---|
| 1779 |
$(TR |
|---|
| 1780 |
$(TH keyword) |
|---|
| 1781 |
$(TH alias type for $(I Identifier)) |
|---|
| 1782 |
) |
|---|
| 1783 |
$(V1 $(TR |
|---|
| 1784 |
$(TD $(CODE typedef)) |
|---|
| 1785 |
$(TD the type that $(I Type) is a typedef of) |
|---|
| 1786 |
) |
|---|
| 1787 |
) |
|---|
| 1788 |
$(TR |
|---|
| 1789 |
$(TD $(CODE struct)) |
|---|
| 1790 |
$(TD $(I Type)) |
|---|
| 1791 |
) |
|---|
| 1792 |
$(TR |
|---|
| 1793 |
$(TD $(CODE union)) |
|---|
| 1794 |
$(TD $(I Type)) |
|---|
| 1795 |
) |
|---|
| 1796 |
$(TR |
|---|
| 1797 |
$(TD $(CODE class)) |
|---|
| 1798 |
$(TD $(I Type)) |
|---|
| 1799 |
) |
|---|
| 1800 |
$(TR |
|---|
| 1801 |
$(TD $(CODE interface)) |
|---|
| 1802 |
$(TD $(I Type)) |
|---|
| 1803 |
) |
|---|
| 1804 |
$(TR |
|---|
| 1805 |
$(TD $(CODE super)) |
|---|
| 1806 |
$(TD $(I TypeTuple) of base classes and interfaces) |
|---|
| 1807 |
) |
|---|
| 1808 |
$(TR |
|---|
| 1809 |
$(TD $(CODE enum)) |
|---|
| 1810 |
$(TD the base type of the enum) |
|---|
| 1811 |
) |
|---|
| 1812 |
$(TR |
|---|
| 1813 |
$(TD $(CODE function)) |
|---|
| 1814 |
$(TD $(I TypeTuple) of the function parameter types) |
|---|
| 1815 |
) |
|---|
| 1816 |
$(TR |
|---|
| 1817 |
$(TD $(CODE delegate)) |
|---|
| 1818 |
$(TD the function type of the delegate) |
|---|
| 1819 |
) |
|---|
| 1820 |
$(TR |
|---|
| 1821 |
$(TD $(CODE return)) |
|---|
| 1822 |
$(TD the return type of the function, delegate, or function pointer) |
|---|
| 1823 |
) |
|---|
| 1824 |
$(V2 |
|---|
| 1825 |
$(TR |
|---|
| 1826 |
$(TD $(CODE const)) |
|---|
| 1827 |
$(TD $(I Type)) |
|---|
| 1828 |
) |
|---|
| 1829 |
$(TR |
|---|
| 1830 |
$(TD $(CODE immutable)) |
|---|
| 1831 |
$(TD $(I Type)) |
|---|
| 1832 |
) |
|---|
| 1833 |
$(TR |
|---|
| 1834 |
$(TD $(CODE shared)) |
|---|
| 1835 |
$(TD $(I Type)) |
|---|
| 1836 |
) |
|---|
| 1837 |
) |
|---|
| 1838 |
) |
|---|
| 1839 |
|
|---|
| 1840 |
------------- |
|---|
| 1841 |
alias short bar; |
|---|
| 1842 |
enum E : byte { Emember } |
|---|
| 1843 |
void foo(bar x) |
|---|
| 1844 |
{ |
|---|
| 1845 |
static if ( $(B is)(bar T == int) ) // not satisfied, short is not int |
|---|
| 1846 |
alias T S; |
|---|
| 1847 |
alias T U; // error, T is not defined |
|---|
| 1848 |
|
|---|
| 1849 |
static if ( $(B is)(E V == enum) ) // satisified, E is an enum |
|---|
| 1850 |
V v; // v is declared to be a byte |
|---|
| 1851 |
} |
|---|
| 1852 |
------------- |
|---|
| 1853 |
|
|---|
| 1854 |
$(V1 |
|---|
| 1855 |
$(P For example, to test to see if $(CODE X) is a typedef and |
|---|
| 1856 |
its base type is int: |
|---|
| 1857 |
) |
|---|
| 1858 |
--- |
|---|
| 1859 |
typedef int X; |
|---|
| 1860 |
|
|---|
| 1861 |
static if (is(X base == typedef)) |
|---|
| 1862 |
{ |
|---|
| 1863 |
static assert(is(base == int), "base of typedef X is not int"); |
|---|
| 1864 |
} |
|---|
| 1865 |
else |
|---|
| 1866 |
{ |
|---|
| 1867 |
static assert(0, "X is not a typedef"); |
|---|
| 1868 |
} |
|---|
| 1869 |
--- |
|---|
| 1870 |
) |
|---|
| 1871 |
) |
|---|
| 1872 |
|
|---|
| 1873 |
$(V2 |
|---|
| 1874 |
$(LI $(B is $(LPAREN)) $(I Type) $(I Identifier) $(B :) $(I TypeSpecialization) $(B ,) $(I TemplateParameterList) $(B $(RPAREN))$(BR) |
|---|
| 1875 |
$(B is $(LPAREN)) $(I Type) $(I Identifier) $(B ==) $(I TypeSpecialization) $(B ,) $(I TemplateParameterList) $(B $(RPAREN)) |
|---|
| 1876 |
|
|---|
| 1877 |
$(P More complex types can be pattern matched; the |
|---|
| 1878 |
$(I TemplateParameterList) declares symbols based on the |
|---|
| 1879 |
parts of the pattern that are matched, analogously to the |
|---|
| 1880 |
way implied template parameters are matched. |
|---|
| 1881 |
) |
|---|
| 1882 |
|
|---|
| 1883 |
--- |
|---|
| 1884 |
import std.stdio; |
|---|
| 1885 |
|
|---|
| 1886 |
void main() |
|---|
| 1887 |
{ |
|---|
| 1888 |
alias long[char[]] AA; |
|---|
| 1889 |
|
|---|
| 1890 |
static if (is(AA T : T[U], U : const char[])) |
|---|
| 1891 |
{ |
|---|
| 1892 |
writefln(typeid(T)); // long |
|---|
| 1893 |
writefln(typeid(U)); // const char[] |
|---|
| 1894 |
} |
|---|
| 1895 |
|
|---|
| 1896 |
static if (is(AA A : A[B], B : int)) |
|---|
| 1897 |
{ |
|---|
| 1898 |
assert(0); // should not match, as B is not an int |
|---|
| 1899 |
} |
|---|
| 1900 |
|
|---|
| 1901 |
static if (is(int[10] W : W[V], int V)) |
|---|
| 1902 |
{ |
|---|
| 1903 |
writefln(typeid(W)); // int |
|---|
| 1904 |
writefln(V); // 10 |
|---|
| 1905 |
} |
|---|
| 1906 |
|
|---|
| 1907 |
static if (is(int[10] X : X[Y], int Y : 5)) |
|---|
| 1908 |
{ |
|---|
| 1909 |
assert(0); // should not match, Y should be 10 |
|---|
| 1910 |
} |
|---|
| 1911 |
} |
|---|
| 1912 |
--- |
|---|
| 1913 |
|
|---|
| 1914 |
) |
|---|
| 1915 |
) |
|---|
| 1916 |
) |
|---|
| 1917 |
|
|---|
| 1918 |
|
|---|
| 1919 |
<h2><a name="associativity">Associativity and Commutativity</a></h2> |
|---|
| 1920 |
|
|---|
| 1921 |
$(P An implementation may rearrange the evaluation of expressions |
|---|
| 1922 |
according to arithmetic associativity and commutativity rules |
|---|
| 1923 |
as long as, within that thread of execution, no observable |
|---|
| 1924 |
difference is possible. |
|---|
| 1925 |
) |
|---|
| 1926 |
|
|---|
| 1927 |
$(P This rule precludes any associative or commutative reordering of |
|---|
| 1928 |
floating point expressions.) |
|---|
| 1929 |
) |
|---|
| 1930 |
|
|---|
| 1931 |
Macros: |
|---|
| 1932 |
TITLE=Expressions |
|---|
| 1933 |
WIKI=Expression |
|---|
| 1934 |
GLINK=$(LINK2 #$0, $(I $0)) |
|---|
| 1935 |
GNAME=<a name=$0>$(I $0)</a> |
|---|
| 1936 |
DOLLAR=$ |
|---|
| 1937 |
FOO= |
|---|