Skip to content

Commit d6bbf61

Browse files
authored
Merge pull request #2004 from wilzbach/1040-function
Revive #1040 - spec/function.d
2 parents f184486 + 044d197 commit d6bbf61

File tree

1 file changed

+174
-13
lines changed

1 file changed

+174
-13
lines changed

spec/function.dd

Lines changed: 174 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,61 @@ int foo();
128128

129129
$(H2 $(LNAME2 pure-functions, Pure Functions))
130130

131-
$(P Pure functions are functions that cannot access global/static
132-
mutable state, except if their arguments contain pointers to such. This
133-
enables optimizations based on the fact that a pure function may at most
134-
mutate state reachable through its parameters. To that end, a pure
135-
function:)
131+
$(P Pure functions are functions that cannot directly access global or static
132+
mutable state. `pure` guarantees that a pure function call
133+
won't access or modify any implicit state in the program.
134+
)
135+
136+
$(P Unlike other functional programming languages, D's `pure`
137+
functions allow modification of the caller state through their mutable
138+
parameters.
139+
)
140+
141+
---
142+
pure int foo(int[] arr) { arr[] += 1; return arr.length; }
143+
int[] a = [1, 2, 3];
144+
foo(a);
145+
assert(a == [2, 3, 4]);
146+
---
147+
148+
$(P A `pure` function accepting parameters with mutable indirections offers
149+
what's called "weak purity" because it can change program state
150+
transitively through its arguments. A `pure` function that has
151+
no parameter with mutable indirections is called "strongly pure"
152+
and fulfills the purity definition in traditional functional languages.
153+
Weakly `pure` functions are useful as reusable building blocks for strongly pure functions.
154+
)
155+
156+
$(P To control mutations, D has the `immutable` type qualifier. If all of
157+
a $(D pure) function's parameters are `immutable` or copied values
158+
without any indirections, it can guarantee that the pure function has
159+
no side effects.
160+
)
161+
$(P To prevent mutation, D offers the `immutable` type qualifier.
162+
If all of a `pure` function's parameters are `immutable` or
163+
copied values without any indirections (e.g. `int`),
164+
the type system guarantees no side effects.
165+
)
166+
167+
---
168+
struct S { double x; }
169+
pure int foo(immutable(int)[] arr, int num, S val)
170+
{
171+
//arr[num] = 1; // compile error
172+
num = 2; // has no side effect to the caller side
173+
val.x = 3.14; // ditto
174+
return arr.length;
175+
}
176+
---
177+
178+
$(P The maximum guarantee of `pure` is called "strong purity". It can enable
179+
optimizations based on the fact
180+
that a function is guaranteed to not mutate anything which isn't passed to it.
181+
For cases where the compiler can guarantee that a pure function cannot
182+
alter its arguments, it can enable full, functional purity (i.e. the guarantee
183+
that the function will always return the same result for the same arguments).
184+
To that end, a pure function:
185+
)
136186

137187
$(UL
138188
$(LI does not read or write any global or static mutable state)
@@ -427,6 +477,35 @@ $(H2 $(LNAME2 inout-functions, Inout Functions))
427477
be matched with inout.
428478
)
429479

480+
$(P $(RELATIVE_LINK2 variadicnested, Nested functions) inside pure function are implicitly marked as pure.
481+
482+
---
483+
pure int foo(int x, immutable int y)
484+
{
485+
int bar()
486+
// implicitly marked as pure, to be "weak purity"
487+
// hidden context pointer is mutable
488+
{
489+
x = 10; // can access states in enclosing scope
490+
// through the mutable context pointer
491+
return x;
492+
}
493+
pragma(msg, typeof(&bar)); // int delegate() pure
494+
495+
int baz() immutable
496+
// qualify hidden context pointer with immutable,
497+
// and has no other parameters, make "strong purity"
498+
{
499+
//return x; // error, cannot access mutable data
500+
// through the immutable context pointer
501+
return y; // ok
502+
}
503+
504+
// can call pure nested functions
505+
return bar() + baz();
506+
}
507+
---
508+
)
430509

431510
$(H2 $(LNAME2 optional-parenthesis, Optional Parentheses))
432511

@@ -2101,7 +2180,7 @@ void main()
21012180

21022181
$(H2 $(LNAME2 interpretation, Compile Time Function Execution (CTFE)))
21032182

2104-
$(P Functions which are both portable and free of side-effects can be
2183+
$(P Functions which are both portable and free of global side-effects can be
21052184
executed at compile time. This is useful when constant folding
21062185
algorithms need to include recursion and looping. Compile time function
21072186
execution is subject to the following restrictions:
@@ -2169,7 +2248,7 @@ $(H2 $(LNAME2 interpretation, Compile Time Function Execution (CTFE)))
21692248
)
21702249

21712250
$(LI
2172-
Any pointer may be cast to $(D void *) and from $(D void *) back to
2251+
Any pointer may be cast to $(D void*) and from $(D void*) back to
21732252
its original type. Casting between pointer and non-pointer types is
21742253
prohibited.
21752254
)
@@ -2188,7 +2267,7 @@ int countTen(int x)
21882267
return x;
21892268
}
21902269

2191-
static assert(countTen(6) == 6); // OK
2270+
static assert(countTen(6) == 6); // OK
21922271
static assert(countTen(12) == 12); // invalid, modifies y.
21932272
---
21942273
$(P The $(D __ctfe) boolean pseudo-variable, which evaluates to $(D_KEYWORD true)
@@ -2205,7 +2284,7 @@ static assert(countTen(12) == 12); // invalid, modifies y.
22052284
example:)
22062285

22072286
$(UL
2208-
$(LI initialization of a static variable)
2287+
$(LI initialization of a static variable or a manifest constant)
22092288
$(LI dimension of a static array)
22102289
$(LI argument for a template value parameter)
22112290
)
@@ -2224,9 +2303,9 @@ int square(int i)
22242303

22252304
void foo()
22262305
{
2227-
static j = square(3); // compile time
2306+
static j = square(3); // compile time
22282307
writeln(j);
2229-
writeln(square(4)); // run time
2308+
writeln(square(4)); // run time
22302309
writeln(eval!(square(5))); // compile time
22312310
}
22322311
---
@@ -2279,6 +2358,84 @@ const int x = foo("1");
22792358
generated. A function template would be the appropriate
22802359
method to implement this sort of thing.)
22812360

2361+
$(H3 $(LNAME2 nogc-functions, No-GC Functions))
2362+
2363+
$(P No-GC functions are functions marked with the $(D @nogc) attribute.
2364+
Those functions do not allocate memory on the GC heap,
2365+
through the following language features:
2366+
)
2367+
2368+
$(UL
2369+
$(LI $(DDSUBLINK expression, ArrayLiteral, constructing an array) on the heap)
2370+
$(LI resizing an array by writing to its $(D .length) property)
2371+
$(LI array $(DDSUBLINK expression, CatExpression, concatenation) and appending)
2372+
$(LI $(DDSUBLINK expression, AssocArrayLiteral, constructing an associative array) on the heap)
2373+
$(LI $(DDSUBLINK expression, IndexExpression, indexing) an associative array
2374+
(because it may throw $(D RangeError) if the specified key is not present))
2375+
$(LI $(DDSUBLINK expression, NewExpression, allocating an object) on the heap)
2376+
$(LI $(DDSUBLINK expression, DeleteExpression, deleting an object) on the heap)
2377+
)
2378+
2379+
---
2380+
@nogc void foo()
2381+
{
2382+
auto a = ['a']; // error, allocates
2383+
a.length = 1; // error, array resizing allocates
2384+
a = a ~ a; // error, arrays concatenation allocates
2385+
a ~= 'c'; // error, appending to arrays allocates
2386+
2387+
auto aa = ["x":1]; // error, allocates
2388+
aa["abc"]; // error, indexing may allocate and throws
2389+
2390+
auto p = new int; // error, operator new allocates
2391+
delete p; // error, operator delete deallocates
2392+
}
2393+
---
2394+
2395+
$(P No-GC functions cannot call functions that are not $(D @nogc).
2396+
)
2397+
2398+
---
2399+
@nogc void foo()
2400+
{
2401+
bar(); // error, bar() may allocate
2402+
}
2403+
2404+
void bar() { }
2405+
---
2406+
2407+
$(P No-GC functions cannot be closures.
2408+
)
2409+
2410+
---
2411+
@nogc int delegate() foo()
2412+
{
2413+
int n; // error, variable n cannot be allocated on heap
2414+
return (){ return n; }
2415+
}
2416+
---
2417+
2418+
$(P $(D @nogc) affects the type of the function. A $(D @nogc)
2419+
function is covariant with a non-$(D @nogc) function.
2420+
)
2421+
2422+
---
2423+
void function() fp;
2424+
void function() @nogc gp; // pointer to @nogc function
2425+
2426+
void foo();
2427+
@nogc void bar();
2428+
2429+
void test()
2430+
{
2431+
fp = &foo; // ok
2432+
fp = &bar; // ok, it's covariant
2433+
gp = &foo; // error, not contravariant
2434+
gp = &bar; // ok
2435+
}
2436+
---
2437+
2438+
22822439
$(H2 $(LNAME2 function-safety, Function Safety))
22832440

22842441
$(P $(I Safe functions) are functions that are statically checked
@@ -2312,6 +2469,10 @@ $(H3 $(LNAME2 safe-functions, Safe Functions))
23122469
$(LI Cannot access $(D __gshared) variables.)
23132470
)
23142471

2472+
$(P When indexing and slicing an array, an out of bounds access
2473+
will cause a runtime error, in order to prevent undefined behavior.
2474+
)
2475+
23152476
$(P Functions nested inside safe functions default to being
23162477
safe functions.
23172478
)
@@ -2361,8 +2522,8 @@ $(H2 $(LNAME2 function-attribute-inference, Function Attribute Inference))
23612522
$(RELATIVE_LINK2 pure-functions, $(D pure)),
23622523
$(RELATIVE_LINK2 nothrow-functions, $(D nothrow)),
23632524
$(RELATIVE_LINK2 safe-functions, $(D @safe)), and
2364-
$(LINK2 attribute.html#nogc, $(D @nogc)) attributes unless
2365-
specifically overridden.
2525+
$(RELATIVE_LINK2 nogc-functions, $(D @nogc))
2526+
attributes unless specifically overridden.
23662527
)
23672528

23682529
$(P Attribute inference is not done for other functions, even if the function

0 commit comments

Comments
 (0)