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/rhai_engine/rhaibook/engine/optimize/eager.md
2025-04-19 08:10:30 +02:00

2.6 KiB

Eager Function Evaluation When Using Full Optimization Level

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

When the optimization level is [OptimizationLevel::Full], the [Engine] assumes all functions to be pure and will eagerly evaluated all function calls with constant arguments, using the result to replace the call.

This also applies to all operators (which are implemented as functions).

// When compiling the following with OptimizationLevel::Full...

const DECISION = 1;
                            //    this condition is now eliminated because 'sign(DECISION) > 0'
if sign(DECISION) > 0       // <- is a call to the 'sign' and '>' functions, and they return 'true'
{
    print("hello!");        // <- this block is promoted to the parent level
} else {
    print("boo!");          // <- this block is eliminated because it is never reached
}

print("hello!");            // <- the above is equivalent to this
                            //    ('print' and 'debug' are handled specially)

Yes! _Very!_

```rust
// Nuclear silo control
if launch_nukes && president_okeyed {
    print("This is NOT a drill!");
    update_defcon(1);
    start_world_war(3);
    launch_all_nukes();
} else {
    print("This is a drill.  Thank you for your cooperation.");
}
```

In the script above (well... as if nuclear silos will one day be controlled by Rhai scripts),
the functions `update_defcon`, `start_world_war` and `launch_all_nukes` will be evaluated
during _compilation_ because they have constant arguments.

The [variables] `launch_nukes` and `president_okeyed` are never checked, because the script
actually has not yet been run!  The functions are called during compilation.
This is, _obviously_, not what you want.

**Moral of the story: compile with an [`Engine`] that does not have any functions registered.
Register functions _AFTER_ compilation.**

Good question! There are two reasons:

* A function call may result in cleaner code than the resultant value.
  In Rust, this would have been handled via a `const` function.

* Evaluating a value to a [custom type] that has no representation in script.

```rust
// A complex function that returns a unique ID based on the arguments
let id = make_unique_id(123, "hello", true);

// The above is arguably clearer than:
//   let id = 835781293546; // generated from 123, "hello" and true

// A custom type that cannot be represented in script
let complex_obj = make_complex_obj(42);
```