Implement closures.
This commit is contained in:
@@ -10,8 +10,6 @@ Keywords List
|
||||
| `let` | Variable declaration | | No |
|
||||
| `const` | Constant declaration | | No |
|
||||
| `is_shared` | Is a value shared? | | No |
|
||||
| `shared` | Share value | [`no_shared`] | No |
|
||||
| `take` | Un-share value | [`no_shared`] | No |
|
||||
| `if` | If statement | | No |
|
||||
| `else` | else block of if statement | | No |
|
||||
| `while` | While loop | | No |
|
||||
@@ -44,6 +42,7 @@ Reserved Keywords
|
||||
| --------- | --------------------- |
|
||||
| `var` | Variable declaration |
|
||||
| `static` | Variable declaration |
|
||||
| `shared` | Share value |
|
||||
| `do` | Looping |
|
||||
| `each` | Looping |
|
||||
| `then` | Control flow |
|
||||
|
@@ -22,7 +22,7 @@ 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):
|
||||
(but they are **NOT** real closures, merely syntactic sugar):
|
||||
|
||||
```rust
|
||||
let obj = #{
|
||||
@@ -50,12 +50,10 @@ fn anon_fn_1002() { print this.data; }
|
||||
```
|
||||
|
||||
|
||||
WARNING - NOT Closures
|
||||
----------------------
|
||||
WARNING - NOT Real Closures
|
||||
--------------------------
|
||||
|
||||
Remember: anonymous functions, though having the same syntax as Rust _closures_, are themselves
|
||||
**not** closures. In particular, they do not capture their execution environment. They are more like
|
||||
Rust's function pointers.
|
||||
|
||||
They do, however, _capture_ variable _values_ from their execution environment, unless the [`no_capture`]
|
||||
feature is turned on. This is accomplished via [automatic currying][capture].
|
||||
**not** real closures.
|
||||
In particular, they capture their execution environment via [automatic currying][capture],
|
||||
unless the [`no_closure`] feature is turned on.
|
||||
|
@@ -15,7 +15,7 @@ is created.
|
||||
|
||||
Variables that are accessible during the time the [anonymous function] is created can be captured,
|
||||
as long as they are not shadowed by local variables defined within the function's scope.
|
||||
The values captured are the values of those variables at the time of the [anonymous function]'s creation.
|
||||
The captured variables are automatically converted into reference-counted shared values.
|
||||
|
||||
|
||||
New Parameters For Captured Variables
|
||||
@@ -29,28 +29,32 @@ In actual implementation, this de-sugars to:
|
||||
|
||||
3. The variable is added to the parameters list of the anonymous function, at the front.
|
||||
|
||||
4. The current value of the variable is then [curried][currying] into the [function pointer] itself, essentially carrying that value and inserting it into future calls of the function.
|
||||
4. The variable is then turned into a reference-counted shared value.
|
||||
|
||||
Automatic currying can be turned off via the [`no_capture`] feature.
|
||||
5. The shared value is then [curried][currying] into the [function pointer] itself, essentially carrying a reference to that shared value and inserting it into future calls of the function.
|
||||
|
||||
Automatic currying can be turned off via the [`no_closure`] feature.
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
```rust
|
||||
let x = 40;
|
||||
let x = 1;
|
||||
|
||||
let f = |y| x + y; // current value of variable 'x' is auto-curried
|
||||
// the value 40 is curried into 'f'
|
||||
let f = |y| x + y; // variable 'x' is auto-curried (captured) into 'f'
|
||||
// 'x' is converted into a shared value
|
||||
|
||||
x = 1; // 'x' can be changed but the curried value is not
|
||||
x = 40; // 'x' can be changed
|
||||
|
||||
f.call(2) == 42; // the value of 'x' is still 40
|
||||
f.call(2) == 42; // the value of 'x' is 40 because 'x' is shared
|
||||
|
||||
// The above de-sugars into this:
|
||||
fn anon$1001(x, y) { x + y } // parameter 'x' is inserted
|
||||
|
||||
let f = Fn("anon$1001").curry(x); // current value of 'x' is curried
|
||||
make_shared(x); // convert 'x' into a shared value
|
||||
|
||||
let f = Fn("anon$1001").curry(x); // shared 'x' is curried
|
||||
|
||||
f.call(2) == 42;
|
||||
```
|
||||
|
@@ -9,7 +9,7 @@ The following are reserved keywords in Rhai:
|
||||
| ------------------------------------------------- | ------------------------------------------------ | --------------------- | :--------------------: |
|
||||
| `true`, `false` | | Boolean constants | |
|
||||
| `let`, `const` | `var`, `static` | Variable declarations | |
|
||||
| `shared`, `take`, `is_shared` | | Shared values | [`no_shared`] |
|
||||
| `is_shared` | | Shared values | [`no_closure`] |
|
||||
| `if`, `else` | `then`, `goto`, `exit` | Control flow | |
|
||||
| | `switch`, `match`, `case` | Matching | |
|
||||
| `while`, `loop`, `for`, `in`, `continue`, `break` | `do`, `each` | Looping | |
|
||||
|
@@ -30,26 +30,33 @@ that resembles very closely that of class methods in an OOP language.
|
||||
|
||||
Anonymous functions can also _capture_ variables from the defining environment, which is a very
|
||||
common OOP pattern. Capturing is accomplished via a feature called _[automatic currying]_ and
|
||||
can be turned off via the [`no_capture`] feature.
|
||||
can be turned off via the [`no_closure`] feature.
|
||||
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
```rust
|
||||
let factor = 1;
|
||||
|
||||
// Define the object
|
||||
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'
|
||||
increment: |x| this.data += x, // 'this' binds to 'obj'
|
||||
update: |x| this.data = x * factor, // 'this' binds to 'obj', 'factor' is captured
|
||||
action: || print(this.data) // 'this' binds to 'obj'
|
||||
};
|
||||
|
||||
// Use the object
|
||||
obj.increment(1);
|
||||
obj.action(); // prints 1
|
||||
obj.action(); // prints 1
|
||||
|
||||
obj.update(42);
|
||||
obj.action(); // prints 42
|
||||
obj.action(); // prints 42
|
||||
|
||||
factor = 2;
|
||||
|
||||
obj.update(42);
|
||||
obj.action(); // prints 84
|
||||
```
|
||||
|
@@ -9,8 +9,7 @@
|
||||
[`no_object`]: {{rootUrl}}/start/features.md
|
||||
[`no_function`]: {{rootUrl}}/start/features.md
|
||||
[`no_module`]: {{rootUrl}}/start/features.md
|
||||
[`no_capture`]: {{rootUrl}}/start/features.md
|
||||
[`no_shared`]: {{rootUrl}}/start/features.md
|
||||
[`no_closure`]: {{rootUrl}}/start/features.md
|
||||
[`no_std`]: {{rootUrl}}/start/features.md
|
||||
[`no-std`]: {{rootUrl}}/start/features.md
|
||||
[`internals`]: {{rootUrl}}/start/features.md
|
||||
|
@@ -23,9 +23,8 @@ more control over what a script can (or cannot) do.
|
||||
| `no_object` | Disable support for [custom types] and [object maps]. |
|
||||
| `no_function` | Disable script-defined [functions]. |
|
||||
| `no_module` | Disable loading external [modules]. |
|
||||
| `no_capture` | Disable [capturing][capture] external variables in [anonymous functions] and [capturing the calling scope]({{rootUrl}}/language/fn-capture.md) in function calls. |
|
||||
| `no_shared` | Disable sharing of data values. |
|
||||
| `no_std` | Build for `no-std` (implies `no_shared`). Notice that additional dependencies will be pulled in to replace `std` features. |
|
||||
| `no_closure` | Disable [capturing][capture] external variables in [anonymous functions] to simulate _closures_, or [capturing the calling scope]({{rootUrl}}/language/fn-capture.md) in function calls. |
|
||||
| `no_std` | Build for `no-std` (implies `no_closure`). Notice that additional dependencies will be pulled in to replace `std` features. |
|
||||
| `serde` | Enable serialization/deserialization via `serde`. Notice that the [`serde`](https://crates.io/crates/serde) crate will be pulled in together with its dependencies. |
|
||||
| `internals` | Expose internal data structures (e.g. [`AST`] nodes). Beware that Rhai internals are volatile and may change from version to version. |
|
||||
| `unicode-xid-ident` | Allow [Unicode Standard Annex #31](http://www.unicode.org/reports/tr31/) as identifiers. |
|
||||
|
Reference in New Issue
Block a user