rhai/doc/src/language/fn-namespaces.md

92 lines
3.2 KiB
Markdown
Raw Normal View History

2020-06-29 23:55:28 +08:00
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.
2020-06-29 23:55:28 +08:00
In general, there are two types of _namespaces_ where functions are looked up:
2020-09-30 23:02:01 +08:00
| 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 |
2020-06-29 23:55:28 +08:00
Global Namespace
----------------
There is one _global_ namespace for every [`Engine`], which includes:
* All the native Rust functions registered via the `Engine::register_XXX` API.
* All the Rust functions defined in [packages] that are loaded into the [`Engine`].
In addition, during evaluation of an [`AST`], all script-defined functions bundled together within
the [`AST`] are added to the global namespace and override any existing registered functions of
the same names and number of parameters.
Anywhere in a Rhai script, when a function call is made, it is searched within the global namespace.
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#"
2020-09-28 22:14:19 +08:00
fn get_message() {
"Hello!" // greeting message
}
2020-06-29 23:55:28 +08:00
fn say_hello() {
2020-09-28 22:14:19 +08:00
print(get_message()); // prints message
2020-06-29 23:55:28 +08:00
}
say_hello();
"#
)?;
// Compile another script with an overriding function
2020-09-24 22:50:28 +08:00
let ast2 = engine.compile(r#"fn get_message() { "Boo!" }"#)?;
2020-06-29 23:55:28 +08:00
// Combine the two AST's
ast1 += ast2; // 'message' will be overwritten
2020-06-29 23:55:28 +08:00
engine.consume_ast(&ast1)?; // prints 'Boo!'
2020-06-29 23:55:28 +08:00
```
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
2020-07-28 10:25:57 +08:00
----------------
| message.rhai |
----------------
2020-09-24 22:50:28 +08:00
fn get_message() { "Hello!" }
2020-06-29 23:55:28 +08:00
2020-07-28 10:25:57 +08:00
---------------
| script.rhai |
---------------
2020-06-29 23:55:28 +08:00
import "message" as msg;
2020-07-28 10:25:57 +08:00
fn say_hello() {
2020-09-24 22:50:28 +08:00
print(msg::get_message());
2020-07-28 10:25:57 +08:00
}
say_hello();
2020-06-29 23:55:28 +08:00
```