Callbacks¶
Functions cross the Dream/JavaScript boundary in both directions: hand a Dream function to JS, or call a JS function from Dream. The runtime wraps Dream function values as ordinary callable JS functions.
At a glance
- Hand a Dream function to JavaScript, or call a JavaScript function from Dream.
- The runtime wraps functions automatically in both directions.
Only non-capturing functions may cross into JS. A capturing lambda would lose its captured state at the boundary. Dream rejects capturing callbacks — use a top-level fun, a captureless lambda, or module-level state instead (see the music player sample).
// el.addEventListener("click", (ev) => { System.println(name); }); // error: capturing callback rejected
Callback forms¶
| Form | Direction | Result |
|---|---|---|
Named fun passed to a dynamic js call |
Dream to JS | Wrapped automatically, with the same wrapper each time for the same function |
js.func(handler) |
Dream to JS | An explicit js callable for a fun(js): void |
js.func0(handler) |
Dream to JS | An explicit js callable for a fun(): void |
| Capturing lambda | Dream to JS | Compile error |
JavaScript function received as a js value |
JS to Dream | Called with ordinary call syntax |
Handlers with two or more js parameters, such as fun(js, js): void, are also wrapped automatically when passed to a dynamic js call.
Registering DOM handlers¶
Passing a Dream function directly into a dynamic js call wraps it automatically:
fun on_click(ev: js): void {
System.println("clicked: " + ev.type.to_str());
}
fun main(): void {
let el = js.global.document.getElementById("app");
el.addEventListener("click", on_click);
}
The wrapper has stable identity per function, so a handler registered with addEventListener can later be removed by passing the same Dream function to removeEventListener. If you need an explicit js callable up front (to store, compare, or pass around first), build one with js.func(handler) / js.func0(handler) (still only with a captureless fun(...)).
JS to Dream¶
A JavaScript function handed to Dream is just a js value — call it with ordinary Dream syntax, and its arguments auto-convert on the way in:
Marshaling¶
Callback arguments and results follow the same conversion rules as dynamic js calls (see Value marshaling and Passing values to JS): primitives and string convert automatically, and JS values travel as js handles.
Try it¶
sample/interop/callbacks.dream runs both directions end to end, with its Node runner callbacks.mjs.