Future specifications
This document uses a specification style to describe features planned or proposed for inclusion in the Starstream language specification once they are finalized and implemented.
Types
- Anonymous enums.
- Utxo types are linear/affine (use exactly once, with including a Utxo in the output either explicit or implicit).
abi MyAbideclares a handle type similar to that ofutxo MyUtxo.- Expand Utxo types, which currently allow constraints on ABI and contract, to allow constraints on tokens as well. Syntax TBD.
- Effects and resumable errors are typed as part of the signature of a function.
- Fatal errors (fail the transaction) are not typed.
Type identities
Structure type definitions can be hashed for comparison. Names do not matter (structural typing).
-
Algebraic Data Types (ADTs) are supported
- Struct identities are based on their field types, in order
- So
(i32, i32)==struct Foo { a: i32, b: i32 }==struct Bar { b: i32, c: i32 } - No such thing as anonymous
{ a: i32, b: i32 }.
- So
- Enum identities are based on their variant discriminators (ordinals), and the field types in order of each variant
- So
i32 | (i32, i32)==enum Foo { A { b: i32, }, C { d: i32, e: i32 } }
- So
- Struct identities are based on their field types, in order
-
Function identities are based on their name and their type.
- Function types are based on their parameter types in order, return type, and possible effect set
Pattern matching
- Expand
letto permit patterns, not just identifiers, with checking that the pattern is irrefutable (usually structs). - Add spread operator
..to ignore remainder of fields.
Semantic environment
The Env of the semantics is defined by the following contexts:
- The instruction context: the program and the instructions left to process
- A suspended UTXO must serialize itself; the VM expects to be able to simply run it from its entry point with its existing memory
- The local memory context: any variables local to the function (ex: "the stack")
- objects can be removed from this context either by going out of scope, or by being used (linear types)
- The persistent memory context: any shared variables that are globally referable (ex: static variables, "the heap")
- Including some notion of when a piece of persistent memory is "freed" and can be safely zeroed (immediately and deterministically)
- The type context: which types exist and their definitions
- There are no pointer types to either functions or resources
- Types have identities (hashes) and are structural (names are omitted when computing the ID)
- The resource context: which references exist to externally-managed resources (tokens)
- UTXO external resources and token intermediates are passed around explicitly, not part of the context
Struct updates
Foo { a: 1, ..old_foo }
Tests
In-script unit and property tests.
Imports
More import sources:
namespace:package/interfacewith optional@1.1.1version- WIT data found at standard(?) search path (ex.
wit/folder) - WIT imports stay imports and must be fulfilled by linking or a runtime extension
- WIT data found at standard(?) search path (ex.
"./path/to/other.star"- Access utxo, token, and ABI types
- Access top-level
library fns, which get embedded/inlined - Access utxo, token, and script fns, which get imported as cross-contract calls
"./path/to/component.wasm"- Embed an arbitrary component as library code
"./path/to/core.wasm"- "unsafe" style FFI imports?
- Or combine with WIT file?
Utxo methods and coroutine lifetimes
The basic flow for a coordination script interacting with a Utxo resembles:
- Coordination script starts
- It calls a Utxo's
main fn, which spawns the Utxo and starts its execution - The
main fnruns until it ends or hits ayield - The Utxo makes itself suspendable by storing locals and program counter to globals / linear memory ("stackless")
- Control flow then returns back to the coordination script caller
- The main-fn call expression evaluates to a handle to the new Utxo
- The contents of the
yielddetermine what methods/ABIs are available- Some methods are resume-ish: consume the Utxo and produce a new one (possibly the handle stays partially valid, depending on syntax sugar)
- These methods can end in one of three ways:
return;to the caller normally while remaining at the sameyieldpointconsume;the utxoresume <expr>;to jump to after theyieldexpression, with its value being that of<expr>
- Calls to these methods conceptually invalidate the Utxo handle and returns a new one, but Utxo flow typing takes this into account
- In Rust terms,
fn(self) -> Self,-> Utxo,-> Option<Utxo>, etc.
- These methods can end in one of three ways:
- Some methods are "normal": they execute in the Utxo's context and can read it (maybe write too?), but not affect its lifetime or ABI set
- Can only
returnnormally - Calls do not invalidate the Utxo handle
- In Rust terms,
fn(&self)andfn(&mut self)
- Can only
- Some methods are resume-ish: consume the Utxo and produce a new one (possibly the handle stays partially valid, depending on syntax sugar)