| CONCEPT |
| inline closures |
| |
| SYNTAX |
| function <returntype> ( <arguments> ) : <context> { <code> } |
| |
| (: <statements> ; <expr>, ... , <expr> :) |
| |
| |
| DESCRIPTION |
| Inline closures are a way to program closures which are |
| compiled at the time an object is loaded, but can access |
| values from their enclosing function at runtime. |
| |
| Example: |
| |
| closure factory (int arg) { |
| return function int (int val) { return val * arg; }; |
| } |
| |
| closure f1 = factory(2); |
| closure f2 = factory(3); |
| funcall(f1, 3) -> will yield 6. |
| funcall(f2, 3) -> will yield 9. |
| |
| The closure here 'inherits' the current value of the local |
| variable 'arg' at the time the closure is created. These |
| values are called the "context" of the closures - they are |
| stored in a special set of variables in the closure. |
| |
| One specific feature of the closure context is that it can be |
| changed from within the closure, and that these changes remain |
| permanent: |
| |
| closure factory (int arg) { |
| return function int (int val) { return val * arg++; }; |
| } |
| |
| closure f = factory(2); |
| funcall(f, 3) -> will yield 6. |
| funcall(f, 3) -> will now yield 9! |
| |
| But changes of the closure context will not reflect on the |
| local variable it was copied from and vice versa. |
| |
| In addition to the implicite context inherited from the |
| defining function, additional context variables can be defined |
| in the closure: |
| |
| closure factory (int arg) { |
| return function int (int val) : int x = 2 * arg |
| { return val * x; }; |
| } |
| |
| closure f = factory(2); |
| funcall(f, 3) -> will yield 12. |
| |
| It is possible to define multiple context variables with and |
| without initialisation: |
| |
| closure factory (int arg) { |
| return function int (int val) : int y, x = 2 * arg; |
| int z |
| { return val * x; }; |
| } |
| |
| These explicite context variables are useful when the closures |
| needs to keep a state, or to improve performance: |
| |
| mapping m = ...; |
| closure slow (int arg) { |
| return function mixed () { return m[arg]; } |
| } |
| closure fast (int arg) { |
| return function mixed () : mixed val = m[arg] { return val; } |
| } |
| |
| In the above example, the fast() function executes the lookup |
| m[arg] only once when the inline closure is created; the |
| slow() function on the other hand returns a closures which |
| looks up m[arg] every time it is called. A second effect is |
| that the results of the slow closure change when m changes; |
| the result of the fast closure is always the same. |
| |
| |
| In the definition of an inline closure, some elements are |
| optional: |
| |
| <returntype> defaults to 'mixed' |
| ( <arguments> ) defaults to '(mixed $1 ... mixed $9)' |
| : <context> no default |
| |
| |
| The special (: :) form is meant for simple expressions (and |
| MudOS compatibility). The form |
| |
| (: <statements> ; <expr>, ..., <expr> :) |
| |
| is the shorthand notation for |
| |
| function { <statements>; return <expr>, ..., <expr>; } |
| |
| For example the two statements |
| |
| sort_array(arr, function { return $1 < $2; } ) |
| sort_array(arr, (: $1 < $2 :) ) |
| |
| do the same. The example also demonstrates that both the <statements> |
| and the <expr> part in this form are optional. |
| |
| |
| |
| NOTES |
| The macro __LPC_INLINE_CLOSURES__ is defined when the |
| inline closures as described here are available. If not |
| defined, the driver implements a more restricted version |
| ('(: :)' syntax only, no context variables) for backwards |
| compatibility. |
| |
| Inline closures are not to be confused with inline functions |
| known from other languages. |
| |
| HISTORY |
| LDMud 3.2.7 implemented the older, restricted form of inline |
| closures. |
| LDMud 3.3.271 implemented the full form of inline closures. |
| LDMud 3.3.275 re-allowed statements in the (: :) form. |
| |
| SEE ALSO |
| closures-abstract(LPC), closures-example(LPC), closure_guide(LPC) |
| closures(LPC) |