Revise docs for 0.19.0.

This commit is contained in:
Stephen Chung
2020-09-30 23:02:01 +08:00
parent a04ed02b54
commit cbc3d8764a
30 changed files with 291 additions and 125 deletions

View File

@@ -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.

View File

@@ -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

View File

@@ -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'

View File

@@ -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

View File

@@ -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

View File

@@ -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)
}
```

View File

@@ -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

View File

@@ -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#"