@@ -178,11 +178,61 @@ int foo();
178
178
179
179
$(H2 $(LNAME2 pure-functions, Pure Functions))
180
180
181
- $(P Pure functions are functions that cannot access global/static
182
- mutable state, except if their arguments contain pointers to such. This
183
- enables optimizations based on the fact that a pure function may at most
184
- mutate state reachable through its parameters. To that end, a pure
185
- function:)
181
+ $(P Pure functions are functions that cannot directly access global or static
182
+ mutable state. `pure` guarantees that a pure function call
183
+ won't access or modify any implicit state in the program.
184
+ )
185
+
186
+ $(P Unlike other functional programming languages, D's `pure`
187
+ functions allow modification of the caller state through their mutable
188
+ parameters.
189
+ )
190
+
191
+ ---
192
+ pure int foo(int[] arr) { arr[] += 1; return arr.length; }
193
+ int[] a = [1, 2, 3];
194
+ foo(a);
195
+ assert(a == [2, 3, 4]);
196
+ ---
197
+
198
+ $(P A `pure` function accepting parameters with mutable indirections offers
199
+ what's called "weak purity" because it can change program state
200
+ transitively through its arguments. A `pure` function that has
201
+ no parameter with mutable indirections is called "strongly pure"
202
+ and fulfills the purity definition in traditional functional languages.
203
+ Weakly `pure` functions are useful as reusable building blocks for strongly pure functions.
204
+ )
205
+
206
+ $(P To control mutations, D has the `immutable` type qualifier. If all of
207
+ a $(D pure) function's parameters are `immutable` or copied values
208
+ without any indirections, it can guarantee that the pure function has
209
+ no side effects.
210
+ )
211
+ $(P To prevent mutation, D offers the `immutable` type qualifier.
212
+ If all of a `pure` function's parameters are `immutable` or
213
+ copied values without any indirections (e.g. `int`),
214
+ the type system guarantees no side effects.
215
+ )
216
+
217
+ ---
218
+ struct S { double x; }
219
+ pure int foo(immutable(int)[] arr, int num, S val)
220
+ {
221
+ //arr[num] = 1; // compile error
222
+ num = 2; // has no side effect to the caller side
223
+ val.x = 3.14; // ditto
224
+ return arr.length;
225
+ }
226
+ ---
227
+
228
+ $(P The maximum guarantee of `pure` is called "strong purity". It can enable
229
+ optimizations based on the fact
230
+ that a function is guaranteed to not mutate anything which isn't passed to it.
231
+ For cases where the compiler can guarantee that a pure function cannot
232
+ alter its arguments, it can enable full, functional purity (i.e. the guarantee
233
+ that the function will always return the same result for the same arguments).
234
+ To that end, a pure function:
235
+ )
186
236
187
237
$(UL
188
238
$(LI does not read or write any global or static mutable state)
@@ -477,6 +527,35 @@ $(H2 $(LNAME2 inout-functions, Inout Functions))
477
527
be matched with inout.
478
528
)
479
529
530
+ $(P $(RELATIVE_LINK2 variadicnested, Nested functions) inside pure function are implicitly marked as pure.
531
+
532
+ ---
533
+ pure int foo(int x, immutable int y)
534
+ {
535
+ int bar()
536
+ // implicitly marked as pure, to be "weak purity"
537
+ // hidden context pointer is mutable
538
+ {
539
+ x = 10; // can access states in enclosing scope
540
+ // through the mutable context pointer
541
+ return x;
542
+ }
543
+ pragma(msg, typeof(&bar)); // int delegate() pure
544
+
545
+ int baz() immutable
546
+ // qualify hidden context pointer with immutable,
547
+ // and has no other parameters, make "strong purity"
548
+ {
549
+ //return x; // error, cannot access mutable data
550
+ // through the immutable context pointer
551
+ return y; // ok
552
+ }
553
+
554
+ // can call pure nested functions
555
+ return bar() + baz();
556
+ }
557
+ ---
558
+ )
480
559
481
560
$(H2 $(LNAME2 optional-parenthesis, Optional Parentheses))
482
561
@@ -2151,7 +2230,7 @@ void main()
2151
2230
2152
2231
$(H2 $(LNAME2 interpretation, Compile Time Function Execution (CTFE)))
2153
2232
2154
- $(P Functions which are both portable and free of side-effects can be
2233
+ $(P Functions which are both portable and free of global side-effects can be
2155
2234
executed at compile time. This is useful when constant folding
2156
2235
algorithms need to include recursion and looping. Compile time function
2157
2236
execution is subject to the following restrictions:
@@ -2219,7 +2298,7 @@ $(H2 $(LNAME2 interpretation, Compile Time Function Execution (CTFE)))
2219
2298
)
2220
2299
2221
2300
$(LI
2222
- Any pointer may be cast to $(D void *) and from $(D void *) back to
2301
+ Any pointer may be cast to $(D void*) and from $(D void*) back to
2223
2302
its original type. Casting between pointer and non-pointer types is
2224
2303
prohibited.
2225
2304
)
@@ -2238,7 +2317,7 @@ int countTen(int x)
2238
2317
return x;
2239
2318
}
2240
2319
2241
- static assert(countTen(6) == 6); // OK
2320
+ static assert(countTen(6) == 6); // OK
2242
2321
static assert(countTen(12) == 12); // invalid, modifies y.
2243
2322
---
2244
2323
$(P The $(D __ctfe) boolean pseudo-variable, which evaluates to $(D_KEYWORD true)
@@ -2255,7 +2334,7 @@ static assert(countTen(12) == 12); // invalid, modifies y.
2255
2334
example:)
2256
2335
2257
2336
$(UL
2258
- $(LI initialization of a static variable)
2337
+ $(LI initialization of a static variable or a manifest constant )
2259
2338
$(LI dimension of a static array)
2260
2339
$(LI argument for a template value parameter)
2261
2340
)
@@ -2274,9 +2353,9 @@ int square(int i)
2274
2353
2275
2354
void foo()
2276
2355
{
2277
- static j = square(3); // compile time
2356
+ static j = square(3); // compile time
2278
2357
writeln(j);
2279
- writeln(square(4)); // run time
2358
+ writeln(square(4)); // run time
2280
2359
writeln(eval!(square(5))); // compile time
2281
2360
}
2282
2361
---
@@ -2329,6 +2408,84 @@ const int x = foo("1");
2329
2408
generated. A function template would be the appropriate
2330
2409
method to implement this sort of thing.)
2331
2410
2411
+ $(H3 $(LNAME2 nogc-functions, No-GC Functions))
2412
+
2413
+ $(P No-GC functions are functions marked with the $(D @nogc) attribute.
2414
+ Those functions do not allocate memory on the GC heap,
2415
+ through the following language features:
2416
+ )
2417
+
2418
+ $(UL
2419
+ $(LI $(DDSUBLINK expression, ArrayLiteral, constructing an array) on the heap)
2420
+ $(LI resizing an array by writing to its $(D .length) property)
2421
+ $(LI array $(DDSUBLINK expression, CatExpression, concatenation) and appending)
2422
+ $(LI $(DDSUBLINK expression, AssocArrayLiteral, constructing an associative array) on the heap)
2423
+ $(LI $(DDSUBLINK expression, IndexExpression, indexing) an associative array
2424
+ (because it may throw $(D RangeError) if the specified key is not present))
2425
+ $(LI $(DDSUBLINK expression, NewExpression, allocating an object) on the heap)
2426
+ $(LI $(DDSUBLINK expression, DeleteExpression, deleting an object) on the heap)
2427
+ )
2428
+
2429
+ ---
2430
+ @nogc void foo()
2431
+ {
2432
+ auto a = ['a']; // error, allocates
2433
+ a.length = 1; // error, array resizing allocates
2434
+ a = a ~ a; // error, arrays concatenation allocates
2435
+ a ~= 'c'; // error, appending to arrays allocates
2436
+
2437
+ auto aa = ["x":1]; // error, allocates
2438
+ aa["abc"]; // error, indexing may allocate and throws
2439
+
2440
+ auto p = new int; // error, operator new allocates
2441
+ delete p; // error, operator delete deallocates
2442
+ }
2443
+ ---
2444
+
2445
+ $(P No-GC functions cannot call functions that are not $(D @nogc).
2446
+ )
2447
+
2448
+ ---
2449
+ @nogc void foo()
2450
+ {
2451
+ bar(); // error, bar() may allocate
2452
+ }
2453
+
2454
+ void bar() { }
2455
+ ---
2456
+
2457
+ $(P No-GC functions cannot be closures.
2458
+ )
2459
+
2460
+ ---
2461
+ @nogc int delegate() foo()
2462
+ {
2463
+ int n; // error, variable n cannot be allocated on heap
2464
+ return (){ return n; }
2465
+ }
2466
+ ---
2467
+
2468
+ $(P $(D @nogc) affects the type of the function. A $(D @nogc)
2469
+ function is covariant with a non-$(D @nogc) function.
2470
+ )
2471
+
2472
+ ---
2473
+ void function() fp;
2474
+ void function() @nogc gp; // pointer to @nogc function
2475
+
2476
+ void foo();
2477
+ @nogc void bar();
2478
+
2479
+ void test()
2480
+ {
2481
+ fp = &foo; // ok
2482
+ fp = &bar; // ok, it's covariant
2483
+ gp = &foo; // error, not contravariant
2484
+ gp = &bar; // ok
2485
+ }
2486
+ ---
2487
+
2488
+
2332
2489
$(H2 $(LNAME2 function-safety, Function Safety))
2333
2490
2334
2491
$(P $(I Safe functions) are functions that are statically checked
@@ -2362,6 +2519,10 @@ $(H3 $(LNAME2 safe-functions, Safe Functions))
2362
2519
$(LI Cannot access $(D __gshared) variables.)
2363
2520
)
2364
2521
2522
+ $(P When indexing and slicing an array, an out of bounds access
2523
+ will cause a runtime error, in order to prevent undefined behavior.
2524
+ )
2525
+
2365
2526
$(P Functions nested inside safe functions default to being
2366
2527
safe functions.
2367
2528
)
@@ -2411,8 +2572,8 @@ $(H2 $(LNAME2 function-attribute-inference, Function Attribute Inference))
2411
2572
$(RELATIVE_LINK2 pure-functions, $(D pure)),
2412
2573
$(RELATIVE_LINK2 nothrow-functions, $(D nothrow)),
2413
2574
$(RELATIVE_LINK2 safe-functions, $(D @safe)), and
2414
- $(LINK2 attribute.html# nogc, $(D @nogc)) attributes unless
2415
- specifically overridden.
2575
+ $(RELATIVE_LINK2 nogc-functions , $(D @nogc))
2576
+ attributes unless specifically overridden.
2416
2577
)
2417
2578
2418
2579
$(P Attribute inference is not done for other functions, even if the function
0 commit comments