Support for anonymous functions.
This commit is contained in:
@@ -163,4 +163,59 @@ x == 42;
|
||||
Beware that this only works for _method-call_ style. Normal function-call style cannot bind
|
||||
the `this` pointer (for syntactic reasons).
|
||||
|
||||
Therefore, obviously, binding the `this` pointer is unsupported under [`no_function`].
|
||||
Therefore, obviously, binding the `this` pointer is unsupported under [`no_object`].
|
||||
|
||||
|
||||
Anonymous Functions
|
||||
-------------------
|
||||
|
||||
Sometimes it gets tedious to define separate functions only to dispatch them via single function pointers.
|
||||
This scenario is especially common when simulating object-oriented programming ([OOP]).
|
||||
|
||||
```rust
|
||||
// Define object
|
||||
let obj = #{
|
||||
data: 42,
|
||||
increment: Fn("inc_obj"), // use function pointers to
|
||||
decrement: Fn("dec_obj"), // refer to method functions
|
||||
print: Fn("print_obj")
|
||||
};
|
||||
|
||||
// Define method functions one-by-one
|
||||
fn inc_obj(x) { this.data += x; }
|
||||
fn dec_obj(x) { this.data -= x; }
|
||||
fn print_obj() { print(this.data); }
|
||||
```
|
||||
|
||||
The above can be replaced by using _anonymous functions_ which have the same syntax as Rust's closures
|
||||
(but they are **NOT** closures, merely syntactic sugar):
|
||||
|
||||
```rust
|
||||
let obj = #{
|
||||
data: 42,
|
||||
increment: |x| this.data += x, // one-liner
|
||||
decrement: |x| this.data -= x,
|
||||
print_obj: || { print(this.data); } // full function body
|
||||
};
|
||||
```
|
||||
|
||||
The anonymous functions will be expanded into separate functions in the global namespace:
|
||||
|
||||
```rust
|
||||
let obj = #{
|
||||
data: 42,
|
||||
increment: Fn("anon_fn_1000"),
|
||||
decrement: Fn("anon_fn_1001"),
|
||||
print: Fn("anon_fn_1002")
|
||||
};
|
||||
|
||||
fn anon_fn_1000(x) { this.data += x; }
|
||||
fn anon_fn_1001(x) { this.data -= x; }
|
||||
fn anon_fn_1002() { print this.data; }
|
||||
```
|
||||
|
||||
### WARNING - NOT Closures
|
||||
|
||||
Remember: anonymous functions, though having the same syntax as Rust _closures_, are themselves
|
||||
**not** closures. In particular, they do not capture their running environment. They are more like
|
||||
Rust's function pointers.
|
||||
|
@@ -20,17 +20,21 @@ to the [object map] before the function is called. There is no way to simulate
|
||||
via a normal function-call syntax because all scripted function arguments are passed by value.
|
||||
|
||||
```rust
|
||||
fn do_action(x) { print(this.data + x); } // 'this' binds to the object when called
|
||||
fn do_action(x) { this.data += x; } // 'this' binds to the object when called
|
||||
|
||||
let obj = #{
|
||||
data: 40,
|
||||
action: Fn("do_action") // 'action' holds a function pointer to 'do_action'
|
||||
action: Fn("do_action") // 'action' holds a function pointer to 'do_action'
|
||||
};
|
||||
|
||||
obj.action(2); // Short-hand syntax: prints 42
|
||||
obj.action(2); // Calls 'do_action' with `this` bound to 'obj'
|
||||
|
||||
// To achieve the above with normal function pointer calls:
|
||||
fn do_action(map, x) { print(map.data + x); }
|
||||
obj.call(obj.action, 2); // The above de-sugars to this
|
||||
|
||||
obj.action.call(obj, 2); // this call cannot mutate 'obj'
|
||||
obj.data == 42;
|
||||
|
||||
// To achieve the above with normal function pointer call will fail.
|
||||
fn do_action(map, x) { map.data += x; } // 'map' is a copy
|
||||
|
||||
obj.action.call(obj, 2); // 'obj' is passed as a copy by value
|
||||
```
|
||||
|
@@ -17,23 +17,22 @@ Rhai's [object maps] has [special support for OOP]({{rootUrl}}/language/object-m
|
||||
| [Object map] properties holding values | properties |
|
||||
| [Object map] properties that hold [function pointers] | methods |
|
||||
|
||||
When a property of an [object map] is called like a method function, and if it happens to hold
|
||||
a valid [function pointer] (perhaps defined via an [anonymous function]), then the call will be
|
||||
dispatched to the actual function with `this` binding to the [object map] itself.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
```rust
|
||||
// Define the object
|
||||
let obj = #{
|
||||
data: 0,
|
||||
increment: Fn("add"), // when called, 'this' binds to 'obj'
|
||||
update: Fn("update"), // when called, 'this' binds to 'obj'
|
||||
action: Fn("action") // when called, 'this' binds to 'obj'
|
||||
};
|
||||
|
||||
// Define functions
|
||||
fn add(x) { this.data += x; } // update using 'this'
|
||||
fn update(x) { this.data = x; } // update using 'this'
|
||||
fn action() { print(this.data); } // access properties of 'this'
|
||||
let obj =
|
||||
#{
|
||||
data: 0,
|
||||
increment: |x| this.data += x, // when called, 'this' binds to 'obj'
|
||||
update: |x| this.data = x, // when called, 'this' binds to 'obj'
|
||||
action: || print(this.data) // when called, 'this' binds to 'obj'
|
||||
};
|
||||
|
||||
// Use the object
|
||||
obj.increment(1);
|
||||
|
@@ -78,6 +78,8 @@
|
||||
[function pointers]: {{rootUrl}}/language/fn-ptr.md
|
||||
[function namespace]: {{rootUrl}}/language/fn-namespaces.md
|
||||
[function namespaces]: {{rootUrl}}/language/fn-namespaces.md
|
||||
[anonymous function]: {{rootUrl}}/language/fn-ptr.md#anonymous-functions
|
||||
[anonymous functions]: {{rootUrl}}/language/fn-ptr.md#anonymous-functions
|
||||
|
||||
[`Module`]: {{rootUrl}}/language/modules/index.md
|
||||
[module]: {{rootUrl}}/language/modules/index.md
|
||||
|
Reference in New Issue
Block a user