Import a Module
See Module Resolvers for more details.
Before a module can be used (via an import
statement) in a script, there must be a
module resolver registered into the Engine
, the default being the FileModuleResolver
.
import
Statement
A module that is only import
-ed but not given any name is simply run.
This is a very simple way to run another script file from within a script.
A module can be imported via the import
statement, and be given a name.
Its members can be accessed via ::
similar to C++.
import "crypto_banner"; // run the script file 'crypto_banner.rhai' without creating an imported module
import "crypto" as lock; // run the script file 'crypto.rhai' and import it as a module named 'lock'
const SECRET_NUMBER = 42;
let mod_file = `crypto_${SECRET_NUMBER}`;
import mod_file as my_mod; // load the script file "crypto_42.rhai" and import it as a module named 'my_mod'
// notice that module path names can be dynamically constructed!
// any expression that evaluates to a string is acceptable after the 'import' keyword
lock::encrypt(secret); // use functions defined under the module via '::'
lock::hash::sha256(key); // sub-modules are also supported
print(lock::status); // module variables are constants
lock::status = "off"; // <- runtime error: cannot modify a constant
Modules imported via import
statements are only accessible inside the relevant block scope.
import "hacker" as h; // import module - visible globally
if secured { // <- new block scope
let mod = "crypt";
import mod + "o" as c; // import module (the path needs not be a constant string)
let x = c::encrypt(key); // use a function in the module
h::hack(x); // global module 'h' is visible here
} // <- module 'c' disappears at the end of the block scope
h::hack(something); // this works as 'h' is visible
c::encrypt(something); // <- this causes a run-time error because
// module 'c' is no longer available!
fn foo(something) {
h::hack(something); // <- this also works as 'h' is visible
}
for x in 0..1000 {
import "crypto" as c; // <- importing a module inside a loop is a Very Bad Idea™
c.encrypt(something);
}
import
statements can appear anywhere a normal statement can be, but in the vast majority of cases they are
usually grouped at the top (beginning) of a script for manageability and visibility.
It is not advised to deviate from this common practice unless there is a Very Good Reason™.
Especially, do not place an import
statement within a loop; doing so will repeatedly re-load the
same module during every iteration of the loop!
Beware of import cycles – i.e. recursively loading the same module. This is a sure-fire way to
cause a stack overflow in the Engine
, unless stopped by setting a limit for maximum number of modules.
For instance, importing itself always causes an infinite recursion:
┌────────────┐
│ hello.rhai │
└────────────┘
import "hello" as foo; // import itself - infinite recursion!
foo::do_something();
Modules cross-referencing also cause infinite recursion:
┌────────────┐
│ hello.rhai │
└────────────┘
import "world" as foo;
foo::do_something();
┌────────────┐
│ world.rhai │
└────────────┘
import "hello" as bar;
bar::do_something_else();