blob: 3a2ecddc6d337cf80324e12d0732a8acfa88dbae [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001CONCEPT
2 inline closures
3
4SYNTAX
5 function <returntype> ( <arguments> ) : <context> { <code> }
6
7 (: <statements> ; <expr>, ... , <expr> :)
8
9
10DESCRIPTION
11 Inline closures are a way to program closures which are
12 compiled at the time an object is loaded, but can access
13 values from their enclosing function at runtime.
14
15 Example:
16
17 closure factory (int arg) {
18 return function int (int val) { return val * arg; };
19 }
20
21 closure f1 = factory(2);
22 closure f2 = factory(3);
23 funcall(f1, 3) -> will yield 6.
24 funcall(f2, 3) -> will yield 9.
25
26 The closure here 'inherits' the current value of the local
27 variable 'arg' at the time the closure is created. These
28 values are called the "context" of the closures - they are
29 stored in a special set of variables in the closure.
30
31 One specific feature of the closure context is that it can be
32 changed from within the closure, and that these changes remain
33 permanent:
34
35 closure factory (int arg) {
36 return function int (int val) { return val * arg++; };
37 }
38
39 closure f = factory(2);
40 funcall(f, 3) -> will yield 6.
41 funcall(f, 3) -> will now yield 9!
42
43 But changes of the closure context will not reflect on the
44 local variable it was copied from and vice versa.
45
46 In addition to the implicite context inherited from the
47 defining function, additional context variables can be defined
48 in the closure:
49
50 closure factory (int arg) {
51 return function int (int val) : int x = 2 * arg
52 { return val * x; };
53 }
54
55 closure f = factory(2);
56 funcall(f, 3) -> will yield 12.
57
58 It is possible to define multiple context variables with and
59 without initialisation:
60
61 closure factory (int arg) {
62 return function int (int val) : int y, x = 2 * arg;
63 int z
64 { return val * x; };
65 }
66
67 These explicite context variables are useful when the closures
68 needs to keep a state, or to improve performance:
69
70 mapping m = ...;
71 closure slow (int arg) {
72 return function mixed () { return m[arg]; }
73 }
74 closure fast (int arg) {
75 return function mixed () : mixed val = m[arg] { return val; }
76 }
77
78 In the above example, the fast() function executes the lookup
79 m[arg] only once when the inline closure is created; the
80 slow() function on the other hand returns a closures which
81 looks up m[arg] every time it is called. A second effect is
82 that the results of the slow closure change when m changes;
83 the result of the fast closure is always the same.
84
85
86 In the definition of an inline closure, some elements are
87 optional:
88
89 <returntype> defaults to 'mixed'
90 ( <arguments> ) defaults to '(mixed $1 ... mixed $9)'
91 : <context> no default
92
93
94 The special (: :) form is meant for simple expressions (and
95 MudOS compatibility). The form
96
97 (: <statements> ; <expr>, ..., <expr> :)
98
99 is the shorthand notation for
100
101 function { <statements>; return <expr>, ..., <expr>; }
102
103 For example the two statements
104
105 sort_array(arr, function { return $1 < $2; } )
106 sort_array(arr, (: $1 < $2 :) )
107
108 do the same. The example also demonstrates that both the <statements>
109 and the <expr> part in this form are optional.
110
111
112
113NOTES
114 The macro __LPC_INLINE_CLOSURES__ is defined when the
115 inline closures as described here are available. If not
116 defined, the driver implements a more restricted version
117 ('(: :)' syntax only, no context variables) for backwards
118 compatibility.
119
120 Inline closures are not to be confused with inline functions
121 known from other languages.
122
123HISTORY
124 LDMud 3.2.7 implemented the older, restricted form of inline
125 closures.
126 LDMud 3.3.271 implemented the full form of inline closures.
127 LDMud 3.3.275 re-allowed statements in the (: :) form.
128
129SEE ALSO
130 closures-abstract(LPC), closures-example(LPC), closure_guide(LPC)
131 closures(LPC)