Ion Fusion Documentation
Release 0.38a1-SNAPSHOT (2026-04-16T19:45:37.790Z)

Module /fusion/eval

Loading and evaluating Fusion code.

Fusion supports dynamic evaluation of code that's loaded or even constructed at runtime. For example, a Fusion application can construct S-expressions denoting some computation, and then evaluate that expression on the fly. The model for performing this evaluation is identical to the behavior of the Read-Eval-Print Loop provided by the Fusion command-line interface. A single dynamic evaluation is like running a very small script. You can run multiple evaluations in sequence while retaining state across the expressions, in effect running a longer script one top-level-form at a time.

As with scripts, such evaluation has a precondition: one needs to specify the language in which the expression is written, to give meaning to the expressions. In this context as with module declarations, that language is defined as a module. The bindings provided by the module form the language and define the semantics of expressions written in that language.

The process for dynamic evaluation involves these steps:

  1. Select the module providing a language for the expressions.
  2. Create a new namespace that uses the language module as its initial bindings.
  3. Evaluate one or more expressions within that namespace.

As step one, construct a module that provides exactly the set of bindings that you wish to have available in the language. Give it an appropriate name and make it available in a repository. For example, here's a very simple language that provides only one operator, named bugbear.

// File FUSION-REPO/src/demo/language.ion

(module language "/fusion"
  (provide bugbear)
  (define (bugbear saying)
    (displayln "Boo! " saying)))

In step two, you'll create a namespace with the language. For example:

(require "/fusion/namespace")
(define ns
  (make_namespace_with_language "/demo/language"))

That code creates a fresh namespace, imports all of the bindings provided by the module /demo/language, and then binds that namespace to the top-level variable ns.

Step three is equally simple. Now that you have a namespace, you can evaluate expressions "inside" it:

(require "/fusion/eval")
(eval (quote (bugbear "Scared ya!")) ns)

... which prints:

Boo! Scared ya!

Since the /demo/language language only exports a single binding, the usual Fusion operators are not visible to the evaluated expressions. The following evaluation will fail:

(eval (quote (+ 1 2)) lang)

Garbage Collection Concerns

A namespace will retain bindings created by any top-level defines, and acts as shared state between evaluations using that namespace. Conversely, evaluation results may retain references to the namespace; in particular, the results of lambda expressions will reference their enclosing namespace because the namespace forms part of the closure's lexical scope. Keep this in mind as you consider the lifetime of the namespaces used for dynamic evaluation. If your expression includes a lambda (either directly or through macro expansion), and if you retain a reference to the resulting closure, you're also retaining a reference to the namespace. This could cause problems if you use one-off namespaces to generate closures, since the namespaces won't be garbage collected until the closures are released. In such situations you may want to reuse a single namespace for multiple evaluations, if you know that the evaluations cannot interfere with each other (say by mutating top-level bindings or other shared state).

eval procedure
(eval top_level_form [namespace])

Evaluates a top_level_form within a namespace. If namespace is absent then the current_namespace parameter is used.

The top_level_form must be a valid top-level syntactic form with respect to the bindings visible in the namespace. The form is expanded, compiled, and evaluated, and its result is returned. Any side effects made to the namespace will be visible to later evaluations.

expand procedure
(expand top_level_form)

Expands a top-level form to core syntax, using the bindings of the current namespace.

The top_level_form may be a syntax object or another datum.

load procedure
(load filename)

Opens the Fusion source file named by the given string and evaluates each expression in sequence, returning the last result. The filename is resolved relative to the value of the current_directory parameter. The evaluation is performed within the current namespace.