Revise docs for 0.19.0.
This commit is contained in:
@@ -49,8 +49,8 @@ f.call!(41); // <- syntax error: capturing is not allowed in method-c
|
||||
No Mutations
|
||||
------------
|
||||
|
||||
Variables in the calling scope are captured as copies.
|
||||
Changes to them do not reflect back to the calling scope.
|
||||
Variables in the calling scope are captured as cloned 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.
|
||||
|
||||
|
||||
@@ -15,10 +15,10 @@ forming a new, combined, group of functions.
|
||||
|
||||
In general, there are two types of _namespaces_ where functions are looked up:
|
||||
|
||||
| Namespace | Source | Lookup method | How Many |
|
||||
| --------- | ---------------------------------------------------------------------- | --------------------------------- | :----------------------: |
|
||||
| Global | `Engine::register_XXX` API, [`AST`] being evaluated, [packages] loaded | simple function name | one |
|
||||
| Module | [`Module`] | namespace-qualified function name | as many as [`import`]-ed |
|
||||
| Namespace | Source | Lookup method | Sub-modules? | Variables? |
|
||||
| --------- | ------------------------------------------------------------------------------------- | ------------------------------ | :----------: | :--------: |
|
||||
| Global | 1) `Engine::register_XXX` API<br/>2) [`AST`] being evaluated<br/>3) [packages] loaded | simple function name | ignored | ignored |
|
||||
| Module | [`Module`] | module-qualified function name | yes | yes |
|
||||
|
||||
|
||||
Global Namespace
|
||||
|
||||
@@ -15,9 +15,10 @@ Built-in methods
|
||||
The following standard methods (mostly defined in the [`BasicFnPackage`][packages] but excluded if
|
||||
using a [raw `Engine`]) operate on [strings]:
|
||||
|
||||
| Function | Parameter(s) | Description |
|
||||
| -------------------------- | ------------ | --------------------------------------------------------------------- |
|
||||
| `name` method and property | _none_ | returns the name of the function encapsulated by the function pointer |
|
||||
| Function | Parameter(s) | Description |
|
||||
| -------------------------- | ------------ | ---------------------------------------------------------------------------- |
|
||||
| `name` method and property | _none_ | returns the name of the function encapsulated by the function pointer |
|
||||
| `call` | _arguments_ | calls the function matching the function pointer's name with the _arguments_ |
|
||||
|
||||
|
||||
Examples
|
||||
@@ -143,7 +144,9 @@ to a function call while binding the object in the method call to the `this` poi
|
||||
To achieve this, pass the `FnPtr` value as the _first_ argument to `call`:
|
||||
|
||||
```rust
|
||||
fn add(x) { this += x; } // define function which uses 'this'
|
||||
fn add(x) { // define function which uses 'this'
|
||||
this += x;
|
||||
}
|
||||
|
||||
let func = Fn("add"); // function pointer to 'add'
|
||||
|
||||
|
||||
@@ -12,8 +12,13 @@ Like C, `continue` can be used to skip to the next iteration, by-passing all fol
|
||||
To loop through a number sequence (with or without steps), use the `range` function to
|
||||
return a numeric iterator.
|
||||
|
||||
|
||||
Iterate Through Strings
|
||||
-----------------------
|
||||
|
||||
Iterating through a [string] yields characters.
|
||||
|
||||
```rust
|
||||
// Iterate through string, yielding characters
|
||||
let s = "hello, world!";
|
||||
|
||||
for ch in s {
|
||||
@@ -23,8 +28,15 @@ for ch in s {
|
||||
|
||||
if x == '@' { break; } // break out of for loop
|
||||
}
|
||||
```
|
||||
|
||||
// Iterate through array
|
||||
|
||||
Iterate Through Arrays
|
||||
----------------------
|
||||
|
||||
Iterating through an [array] yields cloned _copies_ of each element.
|
||||
|
||||
```rust
|
||||
let array = [1, 3, 5, 7, 9, 42];
|
||||
|
||||
for x in array {
|
||||
@@ -34,8 +46,17 @@ for x in array {
|
||||
|
||||
if x == 42 { break; } // break out of for loop
|
||||
}
|
||||
```
|
||||
|
||||
// The 'range' function allows iterating from first to last-1
|
||||
|
||||
Iterate Through Numeric Ranges
|
||||
-----------------------------
|
||||
|
||||
The `range` function allows iterating through a range of numbers
|
||||
(not including the last number).
|
||||
|
||||
```rust
|
||||
// Iterate starting from 0 and stopping at 49.
|
||||
for x in range(0, 50) {
|
||||
if x > 10 { continue; } // skip to the next iteration
|
||||
|
||||
@@ -44,7 +65,7 @@ for x in range(0, 50) {
|
||||
if x == 42 { break; } // break out of for loop
|
||||
}
|
||||
|
||||
// The 'range' function also takes a step
|
||||
// The 'range' function also takes a step.
|
||||
for x in range(0, 50, 3) { // step by 3
|
||||
if x > 10 { continue; } // skip to the next iteration
|
||||
|
||||
@@ -52,8 +73,18 @@ for x in range(0, 50, 3) { // step by 3
|
||||
|
||||
if x == 42 { break; } // break out of for loop
|
||||
}
|
||||
```
|
||||
|
||||
// Iterate through object map
|
||||
|
||||
Iterate Through Object Maps
|
||||
--------------------------
|
||||
|
||||
Two functions, `keys` and `values`, return [arrays] containing cloned _copies_
|
||||
of all property names and values of an [object map], respectively.
|
||||
|
||||
These [arrays] can be iterated.
|
||||
|
||||
```rust
|
||||
let map = #{a:1, b:3, c:5, d:7, e:9};
|
||||
|
||||
// Property names are returned in unsorted, random order
|
||||
|
||||
@@ -42,19 +42,6 @@ add2(42) == 44;
|
||||
```
|
||||
|
||||
|
||||
No Access to External Scope
|
||||
--------------------------
|
||||
|
||||
Functions are not _closures_. They do not capture the calling environment and can only access their own parameters.
|
||||
They cannot access variables external to the function itself.
|
||||
|
||||
```rust
|
||||
let x = 42;
|
||||
|
||||
fn foo() { x } // <- syntax error: variable 'x' doesn't exist
|
||||
```
|
||||
|
||||
|
||||
Global Definitions Only
|
||||
----------------------
|
||||
|
||||
@@ -77,24 +64,52 @@ fn do_addition(x) {
|
||||
```
|
||||
|
||||
|
||||
Use Before Definition
|
||||
--------------------
|
||||
No Access to External Scope
|
||||
--------------------------
|
||||
|
||||
Functions are not _closures_. They do not capture the calling environment
|
||||
and can only access their own parameters.
|
||||
They cannot access variables external to the function itself.
|
||||
|
||||
```rust
|
||||
let x = 42;
|
||||
|
||||
fn foo() { x } // <- syntax error: variable 'x' doesn't exist
|
||||
```
|
||||
|
||||
|
||||
But Can Call Other Functions
|
||||
---------------------------
|
||||
|
||||
All functions in the same [`AST`] can call each other.
|
||||
|
||||
```rust
|
||||
fn foo(x) { x + 1 } // function defined in the global namespace
|
||||
|
||||
fn bar(x) { foo(x) } // OK! function 'foo' can be called
|
||||
```
|
||||
|
||||
|
||||
Use Before Definition Allowed
|
||||
----------------------------
|
||||
|
||||
Unlike C/C++, functions in Rhai can be defined _anywhere_ at global level.
|
||||
|
||||
A function does not need to be defined prior to being used in a script;
|
||||
a statement in the script can freely call a function defined afterwards.
|
||||
|
||||
This is similar to Rust and many other modern languages, such as JavaScript's `function` keyword.
|
||||
|
||||
|
||||
Arguments Passed by Value
|
||||
------------------------
|
||||
Arguments are Passed by Value
|
||||
----------------------------
|
||||
|
||||
Functions defined in script always take [`Dynamic`] parameters (i.e. the parameter can be of any type).
|
||||
Functions defined in script always take [`Dynamic`] parameters (i.e. they can be of any types).
|
||||
Therefore, functions with the same name and same _number_ of parameters are equivalent.
|
||||
|
||||
It is important to remember that all arguments are passed by _value_, so all Rhai script-defined functions
|
||||
are _pure_ (i.e. they never modify their arguments).
|
||||
All arguments are passed by _value_, so all Rhai script-defined functions are _pure_
|
||||
(i.e. they never modify their arguments).
|
||||
|
||||
Any update to an argument will **not** be reflected back to the caller.
|
||||
|
||||
```rust
|
||||
@@ -113,8 +128,8 @@ x == 500; // 'x' is NOT changed!
|
||||
`this` - Simulating an Object Method
|
||||
-----------------------------------
|
||||
|
||||
Functions can also be called in method-call style. When this is the case, the keyword '`this`'
|
||||
binds to the object in the method call and can be changed.
|
||||
Script-defined functions can also be called in method-call style.
|
||||
When this happens, the keyword '`this`' binds to the object in the method call and can be changed.
|
||||
|
||||
```rust
|
||||
fn change() { // not that the object does not need a parameter
|
||||
|
||||
@@ -39,8 +39,8 @@ array[0].update(); // <- call in method-call style will update 'a'
|
||||
**IMPORTANT: Rhai does NOT support normal references (i.e. `&T`) as parameters.**
|
||||
|
||||
|
||||
Number of Parameters
|
||||
--------------------
|
||||
Number of Parameters in Methods
|
||||
------------------------------
|
||||
|
||||
Native Rust methods registered with an [`Engine`] take _one additional parameter_ more than
|
||||
an equivalent method coded in script, where the object is accessed via the `this` pointer instead.
|
||||
@@ -53,15 +53,43 @@ The following table illustrates the differences:
|
||||
| Rhai script | _N_ | `this` (of type `&mut T`) | `Fn(x: U, y: V)` |
|
||||
|
||||
|
||||
`&mut` is Efficient, Except for `ImmutableString`
|
||||
-----------------------------------------------
|
||||
`&mut` is Efficient, Except for `&mut ImmutableString`
|
||||
----------------------------------------------------
|
||||
|
||||
Using a `&mut` first parameter is highly encouraged when using types that are expensive to clone,
|
||||
even when the intention is not to mutate that argument, because it avoids cloning that argument value.
|
||||
|
||||
For example, the `len` method of an [array] has the signature: `Fn(&mut Array) -> INT`.
|
||||
The array itself is not modified in any way, but using a `&mut` parameter avoids a cloning that would
|
||||
otherwise have happened if the signature were `Fn(Array) -> INT`.
|
||||
Even when a function is never intended to be a method - for example an operator,
|
||||
it is still sometimes beneficial to make it method-like (i.e. with a first `&mut` parameter)
|
||||
if the first parameter is not modified.
|
||||
|
||||
For types that are expensive to clone (remember, all function calls are passed cloned
|
||||
copies of argument values), this may result in a significant performance boost.
|
||||
|
||||
For primary types that are cheap to clone (e.g. those that implement `Copy`), including `ImmutableString`,
|
||||
this is not necessary.
|
||||
|
||||
```rust
|
||||
// This is a type that is very expensive to clone.
|
||||
#[derive(Debug, Clone)]
|
||||
struct VeryComplexType { ... }
|
||||
|
||||
// Calculate some value by adding 'VeryComplexType' with an integer number.
|
||||
fn do_add(obj: &VeryComplexType, offset: i64) -> i64 {
|
||||
...
|
||||
}
|
||||
|
||||
engine
|
||||
.register_type::<VeryComplexType>()
|
||||
.register_fn("+", add_pure /* or add_method*/);
|
||||
|
||||
// Very expensive to call, as the 'VeryComplexType' is cloned before each call.
|
||||
fn add_pure(obj: VeryComplexType, offset: i64) -> i64 {
|
||||
do_add(obj, offset)
|
||||
}
|
||||
|
||||
// Efficient to call, as only a reference to the 'VeryComplexType' is passed.
|
||||
fn add_method(obj: &mut VeryComplexType, offset: i64) -> i64 {
|
||||
do_add(obj, offset)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -29,7 +29,15 @@ Modifying an `ImmutableString` causes it first to be cloned, and then the modifi
|
||||
`ImmutableString` should be used in place of `String` for function parameters because using
|
||||
`String` is very inefficient (the `String` argument is cloned during every call).
|
||||
|
||||
A alternative is to use `&str` which maps straight to `ImmutableString`.
|
||||
A alternative is to use `&str` which de-sugars to `ImmutableString`.
|
||||
|
||||
```rust
|
||||
fn slow(s: String) -> i64 { ... } // string is cloned each call
|
||||
|
||||
fn fast1(s: ImmutableString) -> i64 { ... } // cloning 'ImmutableString' is cheap
|
||||
|
||||
fn fast2(s: &str) -> i64 { ... } // de-sugars to above
|
||||
```
|
||||
|
||||
|
||||
String and Character Literals
|
||||
|
||||
@@ -16,8 +16,9 @@ if some_bad_condition_has_happened {
|
||||
throw; // defaults to empty exception text: ""
|
||||
```
|
||||
|
||||
Exceptions thrown via `throw` in the script can be captured by matching `Err(Box<EvalAltResult::ErrorRuntime(` _reason_ `,` _position_ `)>)`
|
||||
with the exception text captured by the first parameter.
|
||||
Exceptions thrown via `throw` in the script can be captured in Rust by matching
|
||||
`Err(Box<EvalAltResult::ErrorRuntime(reason, position)>)` with the exception text
|
||||
captured by `reason`.
|
||||
|
||||
```rust
|
||||
let result = engine.eval::<i64>(r#"
|
||||
|
||||
Reference in New Issue
Block a user