Implement capturing.
This commit is contained in:
@@ -100,21 +100,22 @@ The Rhai Scripting Language
|
||||
8. [Maximum Call Stack Depth](safety/max-call-stack.md)
|
||||
9. [Maximum Statement Depth](safety/max-stmt-depth.md)
|
||||
7. [Advanced Topics](advanced.md)
|
||||
1. [Object-Oriented Programming (OOP)](language/oop.md)
|
||||
2. [Serialization/Deserialization of `Dynamic` with `serde`](rust/serde.md)
|
||||
3. [Script Optimization](engine/optimize/index.md)
|
||||
1. [Capture Scope for Function Call](language/fn-capture.md)
|
||||
2. [Object-Oriented Programming (OOP)](language/oop.md)
|
||||
3. [Serialization/Deserialization of `Dynamic` with `serde`](rust/serde.md)
|
||||
4. [Script Optimization](engine/optimize/index.md)
|
||||
1. [Optimization Levels](engine/optimize/optimize-levels.md)
|
||||
2. [Re-Optimize an AST](engine/optimize/reoptimize.md)
|
||||
3. [Eager Function Evaluation](engine/optimize/eager.md)
|
||||
4. [Side-Effect Considerations](engine/optimize/side-effects.md)
|
||||
5. [Volatility Considerations](engine/optimize/volatility.md)
|
||||
6. [Subtle Semantic Changes](engine/optimize/semantics.md)
|
||||
4. [Low-Level API](rust/register-raw.md)
|
||||
5. [Use as DSL](engine/dsl.md)
|
||||
5. [Low-Level API](rust/register-raw.md)
|
||||
6. [Use as DSL](engine/dsl.md)
|
||||
1. [Disable Keywords and/or Operators](engine/disable.md)
|
||||
2. [Custom Operators](engine/custom-op.md)
|
||||
3. [Extending with Custom Syntax](engine/custom-syntax.md)
|
||||
6. [Eval Statement](language/eval.md)
|
||||
7. [Eval Statement](language/eval.md)
|
||||
8. [Appendix](appendix/index.md)
|
||||
1. [Keywords](appendix/keywords.md)
|
||||
2. [Operators and Symbols](appendix/operators.md)
|
||||
|
@@ -5,6 +5,8 @@ Advanced Topics
|
||||
|
||||
This section covers advanced features such as:
|
||||
|
||||
* [Capture the calling scope]({{rootUrl}}/language/fn-capture.md) in a function call.
|
||||
|
||||
* Simulated [Object Oriented Programming (OOP)][OOP].
|
||||
|
||||
* [`serde`] integration.
|
||||
|
@@ -54,7 +54,7 @@ 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
|
||||
**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`]
|
||||
|
62
doc/src/language/fn-capture.md
Normal file
62
doc/src/language/fn-capture.md
Normal file
@@ -0,0 +1,62 @@
|
||||
Capture The Calling Scope for Function Call
|
||||
==========================================
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
|
||||
Peeking Out of The Pure Box
|
||||
---------------------------
|
||||
|
||||
Rhai functions are _pure_, meaning that they depend on on their arguments and have no
|
||||
access to the calling environment.
|
||||
|
||||
When a function accesses a variable that is not defined within that function's scope,
|
||||
it raises an evaluation error.
|
||||
|
||||
It is possible, through a special syntax, to capture the calling scope - i.e. the scope
|
||||
that makes the function call - and access variables defined there.
|
||||
|
||||
```rust
|
||||
fn foo(y) { // function accesses 'x' and 'y', but 'x' is not defined
|
||||
x += y; // 'x' is modified in this function
|
||||
x
|
||||
}
|
||||
|
||||
let x = 1;
|
||||
|
||||
foo(41); // error: variable 'x' not found
|
||||
|
||||
// Calling a function with a '!' causes it to capture the calling scope
|
||||
|
||||
foo!(41) == 42; // the function can access the value of 'x', but cannot change it
|
||||
|
||||
x == 1; // 'x' is still the original value
|
||||
|
||||
x.method!(); // <- syntax error: capturing is not allowed in method-call style
|
||||
|
||||
// Capturing also works for function pointers
|
||||
|
||||
let f = Fn("foo");
|
||||
|
||||
call!(f, 41) == 42; // must use function-call style
|
||||
|
||||
f.call!(41); // <- syntax error: capturing is not allowed in method-call style
|
||||
```
|
||||
|
||||
|
||||
No Mutations
|
||||
------------
|
||||
|
||||
Variables in the calling scope are accessed as copies.
|
||||
Changes to them do not reflect back to the calling scope.
|
||||
|
||||
Rhai functions remain _pure_ in the sense that they can never mutate their environment.
|
||||
|
||||
|
||||
Caveat Emptor
|
||||
-------------
|
||||
|
||||
Functions relying on the calling scope is a _Very Bad Idea™_ because it makes code almost impossible
|
||||
to reason and maintain, as their behaviors are volatile and unpredictable.
|
||||
|
||||
This usage should be at the last resort.
|
@@ -1,6 +1,8 @@
|
||||
Capture External Variables via Automatic Currying
|
||||
================================================
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
Poor Man's Closures
|
||||
-------------------
|
||||
|
||||
|
@@ -33,7 +33,7 @@ curried.call(2) == 42; // <- de-sugars to 'func.call(21, 2)'
|
||||
Automatic Currying
|
||||
------------------
|
||||
|
||||
[Anonymous functions] defined via a closure syntax _capture_ external variables that are not shadowed inside
|
||||
the function's scope.
|
||||
[Anonymous functions] defined via a closure syntax _capture_ the _values_ of external variables
|
||||
that are not shadowed inside the function's scope.
|
||||
|
||||
This is accomplished via [automatic currying].
|
||||
|
@@ -23,7 +23,7 @@ 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 external variables in [anonymous functions]. |
|
||||
| `no_capture` | Disable [capturing][capture] external variables in [anonymous functions] and [capturing the calling scope]({{rootUrl}}/language/fn-capture.md) in function calls. |
|
||||
| `no_std` | Build for `no-std`. 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. |
|
||||
|
Reference in New Issue
Block a user