Refine docs.
This commit is contained in:
parent
b795ce9f45
commit
2ff3a1fde5
@ -52,7 +52,7 @@ The Rhai Scripting Language
|
||||
1. [Comments](language/comments.md)
|
||||
2. [Values and Types](language/values-and-types.md)
|
||||
1. [Dynamic Values](language/dynamic.md)
|
||||
2. [type-of()](language/type-of.md)
|
||||
2. [type_of()](language/type-of.md)
|
||||
3. [Numbers](language/numbers.md)
|
||||
1. [Operators](language/num-op.md)
|
||||
2. [Functions](language/num-fn.md)
|
||||
|
@ -69,12 +69,12 @@ For example, the following is a SQL-like syntax for some obscure DSL operation:
|
||||
```rust
|
||||
let table = [..., ..., ..., ...];
|
||||
|
||||
// Syntax = calculate $ident$ $ident$ from $expr$ -> $ident$ : $expr$
|
||||
let total = calculate sum price from table -> row : row.weight > 50;
|
||||
// Syntax = calculate $ident$ ( $expr$ -> $ident$ ) => $ident$ : $expr$
|
||||
let total = calculate sum(table->price) => row : row.weight > 50;
|
||||
|
||||
// Note: There is nothing special about those symbols; to make it look exactly like SQL:
|
||||
// Syntax = SELECT $ident$ ( $ident$ ) FROM $expr$ AS $ident$ WHERE $expr$
|
||||
let total = SELECT sum(price) FROM table AS row WHERE row.weight > 50;
|
||||
// Syntax = SELECT $ident$ ( $ident$ ) AS $ident$ FROM $expr$ WHERE $expr$
|
||||
let total = SELECT sum(price) AS row FROM table WHERE row.weight > 50;
|
||||
```
|
||||
|
||||
After registering this custom syntax with Rhai, it can be used anywhere inside a script as
|
||||
@ -84,9 +84,9 @@ For its evaluation, the callback function will receive the following list of inp
|
||||
|
||||
* `inputs[0] = "sum"` - math operator
|
||||
* `inputs[1] = "price"` - field name
|
||||
* `inputs[2] = Expression(table)` - data source
|
||||
* `inputs[3] = "row"` - loop variable name
|
||||
* `inputs[2] = "row"` - loop variable name
|
||||
* `inputs[3] = Expression(table)` - data source
|
||||
* `inputs[4] = Expression(row.wright > 50)` - filter predicate
|
||||
|
||||
Other identifiers, such as `"calculate"`, `"from"`, as well as symbols such as `->` and `:`,
|
||||
Other identifiers, such as `"calculate"`, `"FROM"`, as well as symbols such as `->` and `:` etc.,
|
||||
are parsed in the order defined within the custom syntax.
|
||||
|
@ -6,8 +6,8 @@ Dynamic Values
|
||||
A `Dynamic` value can be _any_ type. However, under [`sync`], all types must be `Send + Sync`.
|
||||
|
||||
|
||||
Use [`type_of()`] to Get Value Type
|
||||
----------------------------------
|
||||
Use `type_of()` to Get Value Type
|
||||
--------------------------------
|
||||
|
||||
Because [`type_of()`] a `Dynamic` value returns the type of the actual value,
|
||||
it is usually used to perform type-specific actions based on the actual value's type.
|
||||
|
@ -65,17 +65,15 @@ disable `eval` by overloading it, probably with something that throws.
|
||||
```rust
|
||||
fn eval(script) { throw "eval is evil! I refuse to run " + script }
|
||||
|
||||
let x = eval("40 + 2"); // 'eval' here throws "eval is evil! I refuse to run 40 + 2"
|
||||
let x = eval("40 + 2"); // throws "eval is evil! I refuse to run 40 + 2"
|
||||
```
|
||||
|
||||
Or overload it from Rust:
|
||||
|
||||
```rust
|
||||
fn alt_eval(script: String) -> Result<(), Box<EvalAltResult>> {
|
||||
engine.register_result_fn("eval", |script: String| -> Result<(), Box<EvalAltResult>> {
|
||||
Err(format!("eval is evil! I refuse to run {}", script).into())
|
||||
}
|
||||
|
||||
engine.register_result_fn("eval", alt_eval);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
|
@ -9,6 +9,9 @@ is provided by the `for` ... `in` loop.
|
||||
Like C, `continue` can be used to skip to the next iteration, by-passing all following statements;
|
||||
`break` can be used to break out of the loop unconditionally.
|
||||
|
||||
To loop through a number sequence (with or without steps), use the `range` function to
|
||||
return a numeric iterator.
|
||||
|
||||
```rust
|
||||
// Iterate through string, yielding characters
|
||||
let s = "hello, world!";
|
||||
|
@ -20,14 +20,15 @@ Global Variables
|
||||
|
||||
The `export` statement, which can only be at global level, exposes selected variables as members of a module.
|
||||
|
||||
Variables not exported are _private_ and hidden to the outside.
|
||||
Variables not exported are _private_ and hidden. They are merely used to initialize the module,
|
||||
but cannot be accessed from outside.
|
||||
|
||||
Everything exported from a module is **constant** (**read-only**).
|
||||
|
||||
```rust
|
||||
// This is a module script.
|
||||
|
||||
let private = 123; // variable not exported - default hidden
|
||||
let hidden = 123; // variable not exported - default hidden
|
||||
let x = 42; // this will be exported below
|
||||
|
||||
export x; // the variable 'x' is exported under its own name
|
||||
@ -43,9 +44,6 @@ export x as answer; // the variable 'x' is exported under the alias 'answer'
|
||||
}
|
||||
```
|
||||
|
||||
[`private`] variables are used to initialize the module.
|
||||
They cannot be used apart from this.
|
||||
|
||||
|
||||
Functions
|
||||
---------
|
||||
|
@ -10,7 +10,7 @@ Unary Operators
|
||||
|
||||
| Operator | Description |
|
||||
| -------- | ----------- |
|
||||
| `+` | Plus |
|
||||
| `+` | Positive |
|
||||
| `-` | Negative |
|
||||
|
||||
```rust
|
||||
|
@ -1,5 +1,5 @@
|
||||
`timestamp`'s
|
||||
=============
|
||||
`timestamp`
|
||||
===========
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
`type_of`
|
||||
=========
|
||||
`type_of()`
|
||||
===========
|
||||
|
||||
{{#include ../links.md}}
|
||||
|
||||
|
@ -137,7 +137,7 @@ For example, the above configuration example may be expressed by this custom syn
|
||||
id "hello";
|
||||
|
||||
// Add to list
|
||||
list +"foo"
|
||||
list + "foo";
|
||||
|
||||
// Add to map
|
||||
map "bar" => true;
|
||||
|
@ -6,8 +6,8 @@ Object-Oriented Programming (OOP)
|
||||
Rhai does not have _objects_ per se, but it is possible to _simulate_ object-oriented programming.
|
||||
|
||||
|
||||
Use [Object Maps] to Simulate OOP
|
||||
--------------------------------
|
||||
Use Object Maps to Simulate OOP
|
||||
------------------------------
|
||||
|
||||
Rhai's [object maps] has [special support for OOP]({{rootUrl}}/language/object-maps-oop.md).
|
||||
|
||||
@ -22,8 +22,8 @@ a valid [function pointer] (perhaps defined via an [anonymous function] or more
|
||||
then the call will be dispatched to the actual function with `this` binding to the [object map] itself.
|
||||
|
||||
|
||||
Use Anonymous Functions to Define Methods
|
||||
----------------------------------------
|
||||
Use Closures to Define Methods
|
||||
-----------------------------
|
||||
|
||||
[Anonymous functions] or [closures] defined as values for [object map] properties take on
|
||||
a syntactic shape that resembles very closely that of class methods in an OOP language.
|
||||
|
@ -5,9 +5,11 @@ Export a Rust Module to Rhai
|
||||
|
||||
|
||||
When applied to a Rust module, the `#[export_module]` attribute generates the necessary
|
||||
code and metadata to allow Rhai access to its public (i.e. marked `pub`) functions. This code
|
||||
is exactly what would need to be written by hand to achieve the same goal, and is custom fit
|
||||
to each exported item.
|
||||
code and metadata to allow Rhai access to its public (i.e. marked `pub`) functions, constants
|
||||
and sub-modules.
|
||||
|
||||
This code is exactly what would need to be written by hand to achieve the same goal,
|
||||
and is custom fit to each exported item.
|
||||
|
||||
This Rust module can then either be loaded into an [`Engine`] as a normal [module] or
|
||||
registered as a [custom package]. This is done by using the `exported_module!` macro.
|
||||
@ -16,15 +18,19 @@ registered as a [custom package]. This is done by using the `exported_module!` m
|
||||
`#[export_module]` and `exported_module!`
|
||||
----------------------------------------
|
||||
|
||||
Apply `#[export_module]` onto a Rust module to convert all `pub` functions into Rhai plugin
|
||||
functions.
|
||||
Apply `#[export_module]` onto a Rust module to register automatically construct a Rhai [module],
|
||||
which can then be loaded into an [`Engine`].
|
||||
|
||||
All `pub` functions become registered functions, all `pub` constants become [module] constant variables,
|
||||
and all sub-modules become Rhai sub-modules.
|
||||
|
||||
```rust
|
||||
use rhai::plugins::*; // a "prelude" import for macros
|
||||
|
||||
#[export_module]
|
||||
mod my_module {
|
||||
// This constant will be registered as a the constant variable 'SOME_NUMBER'.
|
||||
// This constant will be registered as the constant variable 'SOME_NUMBER'.
|
||||
// Ignored when loaded as a package.
|
||||
pub const SOME_NUMBER: i64 = 42;
|
||||
|
||||
// This function will be registered as 'greet'.
|
||||
@ -39,14 +45,23 @@ mod my_module {
|
||||
pub fn increment(num: &mut i64) {
|
||||
*num += 1;
|
||||
}
|
||||
// This function is NOT registered.
|
||||
// This function is not 'pub', so NOT registered.
|
||||
fn mystic_number() -> i64 {
|
||||
42
|
||||
}
|
||||
|
||||
// This sub-module is ignored when loaded as a package.
|
||||
pub mod my_sub_module {
|
||||
// This function is ignored when loaded as a package.
|
||||
// Otherwise it is a valid registered function under a sub-module.
|
||||
pub fn get_info() -> String {
|
||||
"hello".to_string()
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In order to load this into an [`Engine`], use the `load_package` method on the exported module:
|
||||
The simplest way to load this into an [`Engine`] is to use the `load_package` method on the exported module:
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
@ -55,7 +70,7 @@ fn main() {
|
||||
// The macro call creates the Rhai module.
|
||||
let module = exported_module!(my_module);
|
||||
|
||||
// A module can simply be loaded, registering all public its contents.
|
||||
// A module can simply be loaded, registering all public functions.
|
||||
engine.load_package(module);
|
||||
}
|
||||
```
|
||||
@ -77,9 +92,12 @@ increment(x);
|
||||
x == 43;
|
||||
```
|
||||
|
||||
Registering this as a custom package is almost the same, except that a module resolver must
|
||||
point to the module, rather than being loaded directly. See the [module] section for more
|
||||
information.
|
||||
Notice that, when using a [module] as a [package], only functions registered at the _top level_
|
||||
can be accessed. Variables as well as sub-modules are ignored.
|
||||
|
||||
Using this directly as a Rhai module is almost the same, except that a [module resolver] must
|
||||
be used to serve the module, and the module is loaded via `import` statements.
|
||||
See the [module] section for more information.
|
||||
|
||||
|
||||
Function Overloading and Operators
|
||||
@ -91,7 +109,8 @@ attribute to individual functions.
|
||||
The text string given as the `name` parameter to `#[rhai_fn]` is used to register the function with
|
||||
the [`Engine`], disregarding the actual name of the function.
|
||||
|
||||
With `#[rhai_fn(name = "...")]`, multiple functions may be registered under the same name in Rhai, so long as they have different parameters.
|
||||
With `#[rhai_fn(name = "...")]`, multiple functions may be registered under the same name in Rhai,
|
||||
so long as they have different parameters.
|
||||
|
||||
Operators (which require function names that are not valid for Rust) can also be registered this way.
|
||||
|
||||
|
@ -7,7 +7,8 @@ Create a Module from Rust
|
||||
Create via Plugin
|
||||
-----------------
|
||||
|
||||
By far the simplest way to create a [module] is via a [plugin module].
|
||||
By far the simplest way to create a [module] is via a [plugin module]
|
||||
which converts a normal Rust module into a Rhai [module] via procedural macros.
|
||||
|
||||
|
||||
Create via `Module` API
|
||||
@ -21,7 +22,8 @@ For the complete `Module` API, refer to the [documentation](https://docs.rs/rhai
|
||||
Make the `Module` Available to the `Engine`
|
||||
------------------------------------------
|
||||
|
||||
In order to _use_ a custom module, there must be a [module resolver].
|
||||
In order to _use_ a custom module, there must be a [module resolver], which serves the module when
|
||||
loaded via `import` statements.
|
||||
|
||||
The easiest way is to use, for example, the [`StaticModuleResolver`][module resolver] to hold such
|
||||
a custom module.
|
||||
|
@ -58,16 +58,16 @@ def_package!(rhai:MyPackage:"My own personal super package", module, {
|
||||
Create a Custom Package from a Plugin Module
|
||||
-------------------------------------------
|
||||
|
||||
By far the easiest way to create a custom module is to call `Module::merge_flatten` from within
|
||||
`rhai::def_package!` which simply merges in all the functions defined within a [plugin module].
|
||||
By far the easiest way to create a custom module is to call `rhai::plugins::combine_with_exported_module!`
|
||||
from within `rhai::def_package!` which simply merges in all the functions defined within a [plugin module].
|
||||
|
||||
In fact, this exactly is how Rhai's built-in packages, such as `BasicMathPackage`, are implemented.
|
||||
|
||||
`rhai::plugins::combine_with_exported_module!` adds all functions and constants from the
|
||||
[plugins][plugin module] definition into the package itself.
|
||||
Because of the specific requirements of a [package], all sub-modules are _flattened_
|
||||
(i.e. all functions defined within sub-modules are pulled up and registered at the top level instead)
|
||||
and so there will not be any sub-modules added to the package.
|
||||
|
||||
All sub-modules are _flattened_ (i.e. all functions and constants defined within sub-modules are registered
|
||||
at the top level) and so there will not be any sub-modules added to the package.
|
||||
Variables in the [plugin module] are ignored.
|
||||
|
||||
```rust
|
||||
// Import necessary types and traits.
|
||||
@ -81,6 +81,8 @@ use rhai::plugin::*;
|
||||
// Define plugin module.
|
||||
#[export_module]
|
||||
mod my_module {
|
||||
pub const MY_NUMBER: i64 = 42;
|
||||
|
||||
pub fn greet(name: &str) -> String {
|
||||
format!("hello, {}!", name)
|
||||
}
|
||||
@ -107,16 +109,17 @@ def_package!(rhai:MyPackage:"My own personal super package", module, {
|
||||
|
||||
// Merge all registered functions and constants from the plugin module into the custom package.
|
||||
//
|
||||
// Functions in the sub-module 'my_sub_module' are flattened and registered at the top level
|
||||
// instead of in a sub-module.
|
||||
// The sub-module 'my_sub_module' is flattened and its functions registered at the top level.
|
||||
//
|
||||
// The text string name in the middle parameter can be anything and is reserved for future use;
|
||||
// it is recommended to be an ID string that uniquely identifies the module.
|
||||
//
|
||||
// The constant variable, 'MY_NUMBER', is ignored.
|
||||
//
|
||||
// This call ends up registering three functions at the top level of the package:
|
||||
// 1) greet
|
||||
// 2) get_num
|
||||
// 3) get_sub_num (flattened from sub-module 'my_sub_module')
|
||||
// 3) get_sub_num (pulled up from 'my_sub_module')
|
||||
//
|
||||
combine_with_exported_module!(module, "my-functions", my_module));
|
||||
});
|
||||
|
@ -37,7 +37,7 @@ namespace alias specified in an [`import`] statement (see also [modules]).
|
||||
A package is _static_ (i.e. pre-loaded into an [`Engine`]), while a module is _dynamic_ (i.e. loaded with
|
||||
the `import` statement).
|
||||
|
||||
Functions in a package are _flattened_, meaning that functions from sub-modules must be pulled up to the root level.
|
||||
Sub-modules in a package are _flattened_, meaning that functions from them must be pulled up to the root level.
|
||||
In other words, there can be no sub-modules in a package, and everything should reside in one, flat namespace.
|
||||
|
||||
Only functions matter for a package. Constant variables registered in a package are ignored.
|
||||
|
@ -13,23 +13,26 @@ If only a single integer type is needed in scripts - most of the time this is th
|
||||
lots of functions related to other integer types that will never be used. As a result, [`Engine`] creation will be faster
|
||||
because fewer functions need to be loaded.
|
||||
|
||||
The [`only_i32`] and [`only_i64`] features disable all integer types except `i32` or `i64` respectively.
|
||||
|
||||
|
||||
Use Only 32-Bit Numbers
|
||||
----------------------
|
||||
|
||||
If only 32-bit integers are needed - again, most of the time this is the case - using [`only_i32`] disables also `i64`.
|
||||
If only 32-bit integers are needed - again, most of the time this is the case - turn on [`only_i32`].
|
||||
Under this feature, only `i32` is supported as a built-in integer type and no others.
|
||||
|
||||
On 64-bit targets this may not gain much, but on some 32-bit targets this improves performance due to 64-bit arithmetic
|
||||
requiring more CPU cycles to complete.
|
||||
On 64-bit targets this may not gain much, but on certain 32-bit targets this improves performance
|
||||
due to 64-bit arithmetic requiring more CPU cycles to complete.
|
||||
|
||||
|
||||
Minimize Size of `Dynamic`
|
||||
-------------------------
|
||||
|
||||
Turning on [`no_float`], and [`only_i32`] makes the key [`Dynamic`] data type only 8 bytes small on 32-bit targets
|
||||
while normally it can be up to 16 bytes (e.g. on x86/x64 CPU's) in order to hold an `i64` or `f64`.
|
||||
Turning on [`no_float`] and [`only_i32`] on 32-bit targets makes the critical [`Dynamic`] data type only 8 bytes long.
|
||||
Normally [`Dynamic`] can be up to 16 bytes (e.g. on x86/x64 CPU's) in order to hold an `i64` or `f64`.
|
||||
|
||||
Making [`Dynamic`] small helps performance due to better cache efficiency.
|
||||
A small [`Dynamic`] helps performance due to better cache efficiency.
|
||||
|
||||
|
||||
Use `ImmutableString`
|
||||
@ -41,17 +44,17 @@ cloning when passing function arguments.
|
||||
Rhai's internal string type is `ImmutableString` (basically `Rc<String>` or `Arc<String>` depending on the [`sync`] feature).
|
||||
It is cheap to clone, but expensive to modify (a new copy of the string must be made in order to change it).
|
||||
|
||||
Therefore, functions taking `String` parameters should use `ImmutableString` or `&str` (which maps to `ImmutableString`)
|
||||
Therefore, functions taking `String` parameters should use `ImmutableString` or `&str` (both map to `ImmutableString`)
|
||||
for the best performance with Rhai.
|
||||
|
||||
|
||||
Disable Closures
|
||||
----------------
|
||||
|
||||
Support for [closures], including capturing shared values, adds material overhead to script evaluation.
|
||||
Support for [closures] that capture shared variables adds material overhead to script evaluation.
|
||||
|
||||
This is because every data access must be checked whether it is a shared value, and if so, take a read
|
||||
or write lock before reading it.
|
||||
This is because every data access must be checked whether it is a shared value and, if so, take a read
|
||||
lock before reading it.
|
||||
|
||||
Use [`no_closure`] to disable closure and capturing support and optimize the hot path
|
||||
Use [`no_closure`] to disable closure and capturing support to optimize the hot path
|
||||
because there is no need to take locks for shared data.
|
||||
|
@ -11,23 +11,23 @@ Notice that this deviates from Rust norm where features are _additive_.
|
||||
Excluding unneeded functionalities can result in smaller, faster builds as well as
|
||||
more control over what a script can (or cannot) do.
|
||||
|
||||
| Feature | Description |
|
||||
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `unchecked` | Disable arithmetic checking (such as over-flows and division by zero), call stack depth limit, operations count limit and modules loading limit.<br/>Beware that a bad script may panic the entire system! |
|
||||
| `sync` | Restrict all values types to those that are `Send + Sync`. Under this feature, all Rhai types, including [`Engine`], [`Scope`] and [`AST`], are all `Send + Sync`. |
|
||||
| `no_optimize` | Disable [script optimization]. |
|
||||
| `no_float` | Disable floating-point numbers and math. |
|
||||
| `only_i32` | Set the system integer type to `i32` and disable all other integer types. `INT` is set to `i32`. |
|
||||
| `only_i64` | Set the system integer type to `i64` and disable all other integer types. `INT` is set to `i64`. |
|
||||
| `no_index` | Disable [arrays] and indexing features. |
|
||||
| `no_object` | Disable support for [custom types] and [object maps]. |
|
||||
| `no_function` | Disable script-defined [functions]. |
|
||||
| `no_module` | Disable loading external [modules]. |
|
||||
| `no_closure` | Disable [capturing][automatic currying] 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. |
|
||||
| Feature | Additive? | Description |
|
||||
| ------------------- | :-------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `unchecked` | No | Disable arithmetic checking (such as over-flows and division by zero), call stack depth limit, operations count limit and modules loading limit.<br/>Beware that a bad script may panic the entire system! |
|
||||
| `sync` | No | Restrict all values types to those that are `Send + Sync`. Under this feature, all Rhai types, including [`Engine`], [`Scope`] and [`AST`], are all `Send + Sync`. |
|
||||
| `no_optimize` | No | Disable [script optimization]. |
|
||||
| `no_float` | No | Disable floating-point numbers and math. |
|
||||
| `only_i32` | No | Set the system integer type to `i32` and disable all other integer types. `INT` is set to `i32`. |
|
||||
| `only_i64` | No | Set the system integer type to `i64` and disable all other integer types. `INT` is set to `i64`. |
|
||||
| `no_index` | No | Disable [arrays] and indexing features. |
|
||||
| `no_object` | No | Disable support for [custom types] and [object maps]. |
|
||||
| `no_function` | No | Disable script-defined [functions]. |
|
||||
| `no_module` | No | Disable loading external [modules]. |
|
||||
| `no_closure` | No | Disable [capturing][automatic currying] external variables in [anonymous functions] to simulate _closures_, or [capturing the calling scope]({{rootUrl}}/language/fn-capture.md) in function calls. |
|
||||
| `no_std` | No | Build for `no-std` (implies `no_closure`). Notice that additional dependencies will be pulled in to replace `std` features. |
|
||||
| `serde` | Yes | Enable serialization/deserialization via `serde`. Notice that the [`serde`](https://crates.io/crates/serde) crate will be pulled in together with its dependencies. |
|
||||
| `internals` | Yes | Expose internal data structures (e.g. [`AST`] nodes). Beware that Rhai internals are volatile and may change from version to version. |
|
||||
| `unicode-xid-ident` | No | Allow [Unicode Standard Annex #31](http://www.unicode.org/reports/tr31/) as identifiers. |
|
||||
|
||||
|
||||
Example
|
||||
@ -57,7 +57,7 @@ This configuration is perfect for an expression parser in a 32-bit embedded syst
|
||||
Caveat - Features Are Not Additive
|
||||
---------------------------------
|
||||
|
||||
Rhai features are not strictly _additive_ - i.e. they do not only add optional functionalities.
|
||||
Most Rhai features are not strictly _additive_ - i.e. they do not only add optional functionalities.
|
||||
|
||||
In fact, most features are _subtractive_ - i.e. they _remove_ functionalities.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user