Stability
JaiScript 0.5 is a beta: the language and its contract are complete, and it stays 0.x until 1.0. This page sorts the language and the embedding API into what is settled and what a 0.x release may still change.
A settled rule is the contract. Where the implementation departs from one, the implementation is the bug and changes to match; the rule stays. Everything under May change can move in any 0.x release, and anything this page does not mention counts as may change.
Settled: the language
- Value semantics. Assignment, by-value parameters and returns copy. Aliasing exists only where a declaration asks for it: a
T&reference or ashared_ptr<T>handle. A reference that is notconstbinds storage of its own type (int&refuses afloatvariable); aconst T&declaration also binds a temporary, and a value of another type that aTdeclaration takes binds aTmade from it, which lives as long as the reference, as in C++. A store through a reference follows the target's declared type. Copying an instance, array or map copies its values and shares its handles, as C++ does. Value Semantics - The type ladder. A typed slot (
int x) is enforced,autois inferred and then enforced,varstays dynamic. The Type Ladder - Strict checking, always. The checker runs before anything executes. A typed-to-typed mistake it can see fails the load; a value that came through
varfails at run time, wheretry/catchsees it.[[warn_mode]]and[[strict_mode]]apply to a region,externdeclares a name the host provides, andcast<T>,cast<T&>andcast<shared_ptr<T>>are the explicit boundary. A program that runs clean is never rejected. Strict checking - One conversion table. Declarations, assignments, by-value parameters, typed returns and field stores all convert through the same table, with at most one converting constructor per conversion. The table
- Typed containers.
array<T>andmap<K, V>hold what they declare: a store converts by the element rules or raises, nothing demotes silently,array<var>is the dynamic form, a copy into avaror aslicekeeps the element type, map keys never coerce,array<Base>holds subclasses, and handle-typed elements take null. Typed containers - Integers and chars.
intis 64-bit. Overflow raises a catchable error, or wraps in a build that definesJAISCRIPT_WRAP_ON_OVERFLOW, and is never undefined behavior; shifts operate on the 64-bit pattern.charis a byte that enters arithmetic as 0..255 and converts only throughcast. Operators - Evaluation order. A call evaluates its callee, then its arguments left to right, and a by-value argument keeps the value it had when it was evaluated. A binary operator evaluates its left operand first. Errors surface in the same order. Evaluation order
- Captures.
[]captures nothing; named lists are exhaustive; an anonymousfunction(...)expression is the JavaScript form and captures as[&]does. A lambda captures the enclosing function's locals and parameters when it is created: a copy under[=]or[x], the variable itself under[&]or[&x], and a shared capture outlives its frame;[this]captures the instance itself. A global is never captured implicitly; the lambda reads it when it runs. A named function or coroutine declared inside a function body captures nothing: naming an enclosing local in it is a parse error. Lambdas and captures - Names and scopes. Blocks scope as in C++. Inside a method a bare name resolves to a local, then a member, then a global. A namespace is a scope, and a
catchvariable belongs to its block. Name resolution - Modules.
includeis textual and runs each time it is reached.importruns a module once per engine and may appear wherever a statement may; reached again, it re-runs a module whose file has changed on disk. Modules - Access control. Two levels:
public:reaches everyone,private:reaches the declaring class and every class derived from it, andprotected:is a synonym ofprivate:. Access control - Statements and expressions.
switchbreaks by default andfallthrough;continues.++and--work on every lvalue. An assignment expression's value is the value the destination stored. A declaration without an initializer takes its type's default.==compares arrays, maps and instances member by member (a useroperator==first), andsame_objectasks identity. Maps iterate and serialize in key order. - Strings. A
stringis bytes;utf8_stringholds the same bytes and counts characters. UTF-8 text - Coroutines.
coroutineprefixes any function or method spelling; a coroutine runs to eachyieldand is driven by a range-foror advanced withnext()/next(n). Coroutines - Hot reload. Redefining a class migrates its live instances in place, and migration never fails. A source that does not parse or check does not load, and the previous definition keeps running. Hot Reload
- Library and edge rules.
contains,index_of,hasand aswitchcase compare with the language's==(switch (1)matchescase 1.0).to_string(x)uses a class's ownto_string().0.0and-0.0are one map key. A compound assignment on a missing map key starts from the value type's default. A JSON round trip keeps chars and non-string map keys, andfrom_jsonpropagates an error from the class's constructor. A barethrow;with no active exception raises the catchableBare throw with no active exception thrown.A compound assignment with an operand of the wrong type raises one text at every destination. A derived value in a base-typed slot keeps its class (no slicing). Language rules - Operators and methods. A script class overloads binary
+ - * / % & | ^ << >> < > <= >= == != <=>, unary- + ~, and=,[]and(): C++'s set less&& || , -> new delete,!,++,--and the compound assignments, anda op= bisa = a op bthroughoperator op. Truthiness isbool to_bool(), and!vis!to_bool(v). A method is called or bound:obj.methodwithout a call is an error, andreflect::bind(obj, "name")makes the callable. Operators - Two backends, one behavior. The interpreter and the VM produce the same values, output and error text for every program. The one exception is recursion depth: where non-tail recursion meets the recursion error, and the VM reusing a bare self tail call's frame. The parity contract
Settled: embedding
- An engine is an object.
jai::engine::make()returns one, and there is no global state: engines share nothing and run on separate threads without locks. Quickstart - Registration is the allowlist. Beyond the core builtins, a script reaches only the host functions, globals and classes registered on its engine. Three doors
- Per-engine choices. The backend is chosen before an engine's first execute; the check mode can change at any time. Backends
- Limits a script cannot catch. A script cannot catch its way past the execution budget or the memory cap. Safety Rails
- Script errors reach the host. Each way of calling script has one failure route: a call that returns a
checked_result(a script function called throughas_function(), a coroutine handle'snext) reports every failure in the result, whileexecuteandexecute_filethrow (jai::parse_error,jai::static_check_errororjai::runtime_error) and astd::functionfromconvert_script_functionthrows ajai::runtime_error; a signal receiver's error throws out of the emit. Calling script from C++ - Precompiled equals source. Running a
.jaibitebehaves exactly like executing the source it was parsed from. jaibite
May change
- The C++ API's exact shape. Signatures, header paths and helper type names can change between 0.x releases. The model in the list above stays. The documented C++ API is the contract: a call the embedding pages or the reference describe keeps its meaning, and the engine's public members are exactly the calls they describe. What lives in a
detailnamespace,jai::detail::engine_access(the library's door to the engine's own hooks) among it, is the library's own and can change or go in any release. Embedding - Performance. What each construct costs, which shapes the VM compiles to its fastest forms, and every figure on the Performance page. A performance change never changes what a program computes. Performance
- The
.jaibiteformat version. It moves whenever the parser's output changes, and a bite loads only in a build with the same version. Ship bites built by the release that loads them; the automatic disk cache re-parses a stale cache file by itself. Shipping bites - What the checker reports at load. A mistake that raises at run time can become a load error in a later release. A program that runs clean keeps loading clean. Precision map
- Error text wording. The texts in the diagnostics catalog can be reworded. Both backends always raise the same text. Diagnostics
- Serialized data. The layout
to_json,to_binaryand the C++ archives write. Data saved by one 0.x release is not promised to load in the next. Serialization - Parallel admission. Which
parallel_for,parallel_transformandparallel_reducebodies the engine admits; a body it does not admit is refused with a catchable error, never run serially. Results stay deterministic at any worker count. Parallel Loops - String mutators.
to_upper,trimand the other mutating string methods change their receiver in place. Observers vs mutators - Script-extensible objects.
extend(obj, Class)and its host side. extend - Absent syntax. There are no coroutine lambdas. They may be added.