Best Practices
Essential design patterns, memory guidelines, and API recommendations when embedding the Autolang virtual machine into host applications for AI execution.
When to use @js_object
Use @js_object when the object already exists in the host application.
Why @js_object Exists:
Under the hood, @js_object is fundamentally a native JsObject handle. However, rather than forcing scripts to call loose global functions or unstructured string calls, @js_object wraps the reference inside a clean, typed OOP class interface.
- OOP Semantics: Scripts get dot-notation autocomplete, static type safety, and clean method syntax without calling loose functions.
- Zero Field Copying: Autolang stores only the raw JS object handle. Native method calls (e.g.
getName(),setName()) delegate directly to the underlying JS instance withthisbound automatically.
Flexible Bi-directional Type Casting:
Autolang features an intelligent type casting engine between native JavaScript values and internal AObject VM representations. When native JS functions receive parameters or return values:
- Primitives & Data: Numbers, strings, booleans, and arrays cast seamlessly back and forth.
- Host References: Objects marked with
@js_objectbypass value copying — the VM casts and stores the raw JS handle directly. - Zero Boilerplate: Native functions simply return standard JavaScript objects; Autolang handles two-way marshaling and type checking automatically.
Good Candidates for @js_object:
- Database entities and ORM models
- Query builders and fluent filters
- HTTP requests and response objects
- File handles and stream controllers
- External SDK client objects
@js_object
class Product {
fun getName(): String
fun setName(value: String): Void
fun getPrice(): Float
}When to use normal classes
Normal Autolang classes are ideal for small values created and owned entirely by the script.
class Point(
val x: Float,
val y: Float
)Good Candidates for Normal Classes:
- Data Transfer Objects (DTOs)
- Configuration objects
- Mathematical and geometric types
- Temporary script data
Avoid unnecessary copies
Prefer returning @js_object instead of converting large host objects into VM memory structures. Using getter/setter methods on @js_object avoids expensive field-by-field marshaling and eliminates repetitive type casting on subsequent operations.
val user = db.findUser(1)
println(user.getName()) // @js_object reference, zero copyingval user = db.findUser(1)
println(user.name) // if user was copied field-by-fieldDesign small native APIs
Expose only the specific operations the AI actually needs. Avoid exposing large generic APIs that grant unnecessary system access.
@js_object
class Product {
fun getName(): String
fun setName(value: String): Void
fun getPrice(): Float
}Prefer fluent APIs
Objects representing builders or queries work naturally with method chaining (Fluent APIs). Fluent syntax is significantly easier for Large Language Models to generate accurately without syntax errors or variable misplacements.
Implementing Fluent APIs with @js_object:
1. Define each builder method in the @js_object class to return the class instance type (e.g. Query).
2. In the host JavaScript implementation, return this from each builder method.
3. Expose a single execution method (e.g. execute()) to trigger the host action.
// Host Registration
compiler.registerBuiltInLibrary("db", `
@js_object
class Query {
@native("query_where")
fun where(field: String, value: String): Query
@native("query_order")
fun orderBy(field: String, direction: String): Query
@native("query_limit")
fun limit(count: Int): Query
@native("query_exec")
fun execute(): Array<Product>
}
`, { autoImport: true }, {
query_where(field, value) { return this.where(field, value); },
query_order(field, dir) { return this.orderBy(field, dir); },
query_limit(count) { return this.limit(count); },
query_exec() { return this.execute(); }
});
// AI Script Usage
val products = Database.createQuery()
.where("status", "completed")
.orderBy("amount", "desc")
.limit(10)
.execute()Restrict AI capabilities
Keep libraries focused. Avoid monolithic system libraries — prefer modular single-responsibility libraries such as mail, database, storage, and report.
Memory management
Use setManagedMemory() on the host compiler to cap the maximum memory budget available for Autolang-managed heap allocations. Host-owned objects wrapped in @js_object remain outside VM memory accounting.
Learn more in the Security & Sandboxing Guide.
Common mistakes
Avoid: Copying every host object into Autolang
Return a @js_object whenever the host already owns the underlying object.
Avoid: Registering an entire SDK
Register only the specific capability functions AI scripts should invoke.
Avoid: Exposing unrestricted file or network access
Enable only the specific capability interfaces required for the task workflow.
Rule of Thumb
| Use Case | Choose |
|---|---|
| Small immutable data | Normal Autolang class |
| Host-owned objects | @js_object |
| Large database entities | @js_object |
| Builders / ORM query objects | @js_object |
| Script-only transient values | Normal class |
