Go Integration
Embed Scriptling in a Go application: create interpreters, choose which libraries scripts can import, and expose your own Go functions, classes, and libraries.
go get github.com/paularlott/scriptlingNew to embedding? The Go embedding quick start runs a first script in a few lines; Basics then covers the full interpreter API. Focused examples on the pages below assume an initialized p as shown there.
Reading Order
- Basics: create interpreters, exchange variables, call script functions, capture output, set resource limits.
- Library Registration: register standard and extended libraries, and set filesystem and network policy before untrusted scripts run.
- Script Extensions: extend the host with libraries written in Scriptling itself.
- Extending in Go: pick an API (see below), then follow its pages.
- Further topics: Library Loader Chain, Plugin Manager (executable plugins in an embedded host), Documenting Extensions, Checking Script Requirements, Linting, GC Release Hooks.
To run Scriptling itself as a server instead of embedding it, use the CLI server guides.
Native vs Builder: Which to Use
The two APIs interoperate: FunctionBuilder.Build() returns an ordinary native function, and LibraryBuilder/ClassBuilder produce the same *object.Library and *object.Class values the Native API uses. Mix them freely, for example a builder library that exposes a native class, or a builder class inheriting from a native one.
| Native API | Builder API | |
|---|---|---|
| You write | func(ctx, kwargs, args ...object.Object) object.Object |
Ordinary Go funcs, e.g. func(a, b int) int |
| Argument checks and conversion | Manual (AsInt, kwargs.GetString, …) |
Automatic from the Go signature |
| Overhead | Direct object handling | Signature cached at build time; common shapes use fast wrappers, others fall back to reflect.Call |
| Best for | Measured hot paths; variable, optional, or mixed-type arguments | Most typed integrations |
Start with the Builder API for typical functions and libraries. Switch a function to the Native API when a benchmark of your real workload shows conversion cost matters, or when you need full control over arguments and return objects. Scriptling’s own libraries use both.
// Native
p.RegisterFunc("add", func(ctx context.Context, kwargs object.Kwargs, args ...object.Object) object.Object {
a, _ := args[0].AsInt()
b, _ := args[1].AsInt()
return object.NewInteger(a + b)
})
// Builder
fb := object.NewFunctionBuilder()
fb.FunctionWithHelp(func(a, b int) int { return a + b }, "add(a, b) - Add two numbers")
p.RegisterFunc("add", fb.Build())Performance Tips
- Choose a lifecycle deliberately - Reuse as-is only for one persistent script session; call
Reset()between unrelated jobs orClone()for isolated interpreters - Load Only Needed Libraries - Don’t load JSON/HTTP if not needed
- Batch Operations - Execute larger scripts rather than many small ones
- Pre-register Functions - Register all Go functions before execution
- Measure Hot Paths - Builder signatures are cached and common shapes use fast wrappers; compare Native and Builder APIs with your workload
// Reuse registrations while clearing script globals between unrelated jobs.
p := scriptling.New()
stdlib.RegisterAll(p)
for _, source := range scripts {
_, err := p.Eval(source)
p.Reset()
if err != nil {
return err
}
}For a stateful session, omit Reset() so globals and imports persist. See Interpreter lifecycle for ResetEnv and Clone choices.