117 lines
4.4 KiB
Markdown
117 lines
4.4 KiB
Markdown
Function Namespaces
|
|
==================
|
|
|
|
{{#include ../links.md}}
|
|
|
|
Each Function is a Separate Compilation Unit
|
|
-------------------------------------------
|
|
|
|
[Functions] in Rhai are _pure_ and they form individual _compilation units_.
|
|
This means that individual functions can be separated, exported, re-grouped, imported,
|
|
and generally mix-'n-match-ed with other completely unrelated scripts.
|
|
|
|
For example, the `AST::merge` and `AST::combine` methods (or the equivalent `+` and `+=` operators)
|
|
allow combining all functions in one [`AST`] into another, forming a new, unified, group of functions.
|
|
|
|
In general, there are two types of _namespaces_ where functions are looked up:
|
|
|
|
| Namespace | How Many | Source | Lookup method | Sub-modules? | Variables? |
|
|
| --------- | :------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | :----------: | :--------: |
|
|
| Global | One | 1) [`AST`] being evaluated<br/>2) `Engine::register_XXX` API<br/>3) [packages] loaded<br/>4) functions in [modules] loaded via `Engine::register_module` and marked _global_ | simple function name | ignored | ignored |
|
|
| Module | Many | [`Module`] | namespace-qualified function name | yes | yes |
|
|
|
|
|
|
Module Namespace
|
|
----------------
|
|
|
|
There can be multiple module namespaces at any time during a script evaluation, loaded via the
|
|
[`import`] statement.
|
|
|
|
Functions and variables in module namespaces are isolated and encapsulated within their own environments.
|
|
|
|
They must be called or accessed in a _namespace-qualified_ manner.
|
|
|
|
```rust
|
|
import "my_module" as m; // new module namespace 'm' created via 'import'
|
|
|
|
let x = m::calc_result(); // namespace-qualified function call
|
|
|
|
let y = m::MY_NUMBER; // namespace-qualified variable (constant) access
|
|
|
|
let x = calc_result(); // <- error: function 'calc_result' not found
|
|
// in global namespace!
|
|
```
|
|
|
|
|
|
Global Namespace
|
|
----------------
|
|
|
|
There is one _global_ namespace for every [`Engine`], which includes (in the following search order):
|
|
|
|
* All functions defined in the [`AST`] currently being evaluated.
|
|
|
|
* All native Rust functions and iterators registered via the `Engine::register_XXX` API.
|
|
|
|
* All functions and iterators defined in [packages] that are loaded into the [`Engine`].
|
|
|
|
* Functions defined in [modules] loaded via `Engine::register_module` that are specifically marked
|
|
for exposure to the global namespace (e.g. via the `#[rhai(global)]` attribute in a [plugin module]).
|
|
|
|
Anywhere in a Rhai script, when a function call is made, the function is searched within the
|
|
global namespace, in the above search order.
|
|
|
|
Therefore, function calls in Rhai are _late_ bound - meaning that the function called cannot be
|
|
determined or guaranteed and there is no way to _lock down_ the function being called.
|
|
This aspect is very similar to JavaScript before ES6 modules.
|
|
|
|
```rust
|
|
// Compile a script into AST
|
|
let ast1 = engine.compile(
|
|
r#"
|
|
fn get_message() {
|
|
"Hello!" // greeting message
|
|
}
|
|
|
|
fn say_hello() {
|
|
print(get_message()); // prints message
|
|
}
|
|
|
|
say_hello();
|
|
"#
|
|
)?;
|
|
|
|
// Compile another script with an overriding function
|
|
let ast2 = engine.compile(r#"fn get_message() { "Boo!" }"#)?;
|
|
|
|
// Combine the two AST's
|
|
ast1 += ast2; // 'message' will be overwritten
|
|
|
|
engine.consume_ast(&ast1)?; // prints 'Boo!'
|
|
```
|
|
|
|
Therefore, care must be taken when _cross-calling_ functions to make sure that the correct
|
|
functions are called.
|
|
|
|
The only practical way to ensure that a function is a correct one is to use [modules] -
|
|
i.e. define the function in a separate module and then [`import`] it:
|
|
|
|
```rust
|
|
----------------
|
|
| message.rhai |
|
|
----------------
|
|
|
|
fn get_message() { "Hello!" }
|
|
|
|
|
|
---------------
|
|
| script.rhai |
|
|
---------------
|
|
|
|
import "message" as msg;
|
|
|
|
fn say_hello() {
|
|
print(msg::get_message());
|
|
}
|
|
say_hello();
|
|
```
|