this – Simulating an Object Method

Functions are pure

The only way for a script-defined function to change an external value is via this.

Arguments passed to script-defined functions are always by value because functions are pure.

However, functions can also be called in method-call style:

object . method ( parameters)

When a function is called this way, the keyword this binds to the object in the method call and can be changed.

fn change() {       // note that the method does not need a parameter
    this = 42;      // 'this' binds to the object in method-call
}

let x = 500;

x.change();         // call 'change' in method-call style, 'this' binds to 'x'

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

change();           // <- error: 'this' is unbound

Elvis Operator

The Elvis operator can be used to short-circuit the method call when the object itself is ().

object ?. method ( parameters)

In the above, the method is never called if object is ().

Bind to this for Module Functions

The method-call syntax is not possible for functions imported from modules.

import "my_module" as foo;

let x = 42;

x.foo::change_value(1);     // <- syntax error

In order to call a module function as a method, export that method as a function pointer and use the call syntax:

┌────────────────┐
│ my_module.rhai │
└────────────────┘

// The actual function that uses 'this'
private fn change_value_impl(offset) {
    this += offset;
}

// Export it as a function pointer
export const change_value = change_value_impl;

// The above is equivalent to:
export const change_value = Fn("change_value_impl");

// Or do it in one step via a closure
export const change_value = |offset| this += offset;


┌───────────┐
│ main.rhai │
└───────────┘

import "my_module" as foo;

let x = 42;

// Use 'call' to bind 'x' to 'this'
x.call(foo::change_value, 1);

x == 43;