This repository has been archived on 2025-08-04. You can view files and clone it, but cannot push or open issues or pull requests.
rhaj/_archive/rhai_engine/rhaibook/language/fn-parent-scope.md
2025-04-04 08:28:07 +02:00

3.0 KiB
Raw Blame History

Call a Function Within the Caller's Scope

{{#include ../links.md}}

Peeking Out of The Pure Box


This is only meaningful for _scripted_ [functions].

Native Rust functions can never access any [`Scope`].

Rhai [functions] are pure, meaning that they depend on on their arguments and have no access to the calling environment.

When a [function] accesses a [variable] that is not defined within that [function]'s [Scope], it raises an evaluation error.

It is possible, through a special syntax, to actually run the [function] call within the [Scope] of the parent caller i.e. the [Scope] that makes the [function] call and access/mutate [variables] defined there.

fn foo(y) {             // function accesses 'x' and 'y', but 'x' is not defined
    x += y;             // 'x' is modified in this function
    let z = 0;          // 'z' is defined in this function's scope
    x
}

let x = 1;              // 'x' is defined here in the parent scope

foo(41);                // error: variable 'x' not found

// Calling a function with a '!' causes it to run within the caller's scope

foo!(41) == 42;         // the function can access and mutate the value of 'x'!

x == 42;                // 'x' is changed!

z == 0;                 // <- error: variable 'z' not found

x.method!();            // <- syntax error: not allowed in method-call style

// Also works for function pointers

let f = foo;            // <- de-sugars to 'Fn("foo")'

call!(f, 42) == 84;     // must use function-call style

x == 84;                // 'x' is changed once again

f.call!(41);            // <- syntax error: not allowed in method-call style

// But not allowed for module functions

import "hello" as h;

h::greet!();            // <- syntax error: not allowed in namespace-qualified calls

Changes to [variables] in the calling [`Scope`] persist.

With this syntax, it is possible for a Rhai [function] to mutate its calling environment.

[Variables] or [constants] defined within the [function] are _not_ retained.
They remain local to the [function].

Although the syntax resembles a Rust _macro_ invocation, it is still a [function] call.

[Functions] relying on the calling [`Scope`] is often a _Very Bad Idea™_ because it makes code
almost impossible to reason about and maintain, as their behaviors are volatile and unpredictable.

Rhai [functions] are normally _pure_, meaning that you can rely on the fact that they never mutate
the outside environment.  Using this syntax breaks this guarantee.

[Functions] called in this manner behave more like macros that are expanded inline than actual
function calls, thus the syntax is also similar to Rust's macro invocations.

This usage should be at the last resort.

**YOU HAVE BEEN WARNED**.