Helpers for building interface-style wrappers and concrete implementations over named method descriptions.
Model
Method descriptions name parameters and results. interface turns them into a vtable of Code values and an interface base object of forwarding members.
implement turns an interface-base supplier (@Mover) and a concrete-object supplier into a factory; its CALL constructs concrete objects containing base and the supplied fields.
obj.base is the borrowed interface view accepted where the interface is expected.
The factory owns the vtable; keep it alive and unmoved while its objects or views use it.
interface
(getMethods -- interfaceFactory) Builds a callable factory from a method-description supplier.- Calling the factory constructs an interface base object with a vtable reference, DIE, SIZE, and forwarding members.
Generated interface shape
Method-description grammar
getMethodsis called to obtain a Struct whose named fields describe methods. Each method description is a nonempty Struct: all fields except the last describe parameters, and the last describes the result. The result field's name is not special.- Use
()as the result descriptor for no output; a Struct result is one Struct object, not several stack outputs. - Parameter and result schemas are obtained with
cloneField. UseRef/Creffields to request reference parameters or results. GeneratedCodeprepends aNatxself address. - A call through a base member, such as
y x @object.base.method, for{x: Int32; y: Int32; result: Int32;}, supplies explicit arguments in reverse description order; the selected forwarding member has effect(y x -- result). A direct call to the corresponding vtable Code additionally takes the concrete object'sNatxaddress on top:(y x selfAddress -- result). - An empty method collection is permitted; an individual method still needs its final result field.
Generated fields
Interface factory
Vtable: the stored vtable object.CALL: a static Block with effect(-- base)that constructs an interface base object. Factory CALL returns a non-reference object.
Vtable
DIE_FUNC: Code with effect(selfAddress --); its initial implementation does nothing.SIZE: Code with effect(selfAddress -- byteCount)returningNatx.- Each declared method has its generated Code signature. SIZE and ordinary method entries are initially NIL, not usable implementations.
Interface base
vtable: a stored reference to the Vtable.DIE: generated destruction forwarding through DIE_FUNC.SIZE: generated forwarding of the concrete representation's storage size.- Named forwarding members are callable Dicts with static NAME and CALL. A declared method named CALL is instead exposed as the base object's CALL Block.
implement
(getBase getObject -- implementationFactory) Builds a callable implementation factory using an interface-base supplier and a concrete-object supplier.- Calling the factory constructs a concrete object with a base view and the supplied fields.
Remarks
getObjectis processed while forming the factory and while constructing instances; see implementation lifetime.
Generated implementation shape
Implementation factory
Base: the static interface-base descriptor.getObject: the concrete-object supplier.vtable: the populated vtable.CALL: a static Block with effect(-- concrete). It constructs a concrete object; it does not merely return a schema or a borrowed base. Factory CALL returns a non-reference object.
Concrete object and base adapter
- The concrete object contains
basefollowed by the supplied fields in source order. - The
getObjectStruct supplies a member under each declared method name. The generated function selects that member withcallField, and its resulting stack must match the declared signature. - A Block is called with the concrete fields in scope, so
move: [offset +]reads the fieldoffset; a Code receives the declared parameters and no extra self parameter, as inmove: {value: Int32;} Int32 {} codeRef; [1 +] !move. A callable Dict or a matching value/reference member is also valid. - Forming the implementation writes into every method entry a function with effect
(parameters... selfAddress -- result)that reconstructs the concrete object fromselfAddressand appliescallFieldto that member. - The base adapter stores static Base, a reference to the implementation vtable, and CALL with effect
(-- baseRef). Calling the adapter —obj.base(immutable view) or@obj.base(mutable view) — produces a borrowed interface view of the concrete object's storage;@obj.@basereads the adapter itself without calling it.
Result and view rules
- Results have the declared result schema. Value results are returned as values; Ref/Cref results remain references with their declared mutability. A reference result can alias the concrete object and must not outlive its target.
- Forwarding does not infer constness from an immutable base view. The concrete self address is used for dispatch, and a method declared to return Ref or mutate state can still do so through such a view. Use an explicitly read-only interface contract where needed.
Implementation lifetime
- Base objects returned by an interface factory borrow its vtable; concrete objects returned by an implementation factory borrow that factory's vtable. Keep the relevant factory and vtable storage alive and unmoved while those objects or views use them. A concrete object's base view borrows that object's storage; it is not a separate independently destroyable copy.
- Concrete fields are reconstructed individually. Stored references retain their targets; non-Ref fields use copy/move construction according to their views and support. Private fields become public, and an explicit static qualifier on a non-Meta field is not retained. Meta fields remain inherently static. This is neither a whole-object ownership move nor a generic deep copy.
getObjectis processed while forming the implementation as well as when constructing instances. Supplier runtime effects and cleanup can occur during factory construction; do not use it as an exactly-once acquisition hook.- The generated destructor destroys the complete concrete representation, not just the base adapter. Do not destroy both a base view and its still-live concrete owner. Borrowed reference fields do not transfer ownership of their targets.
Validation and reserved names
- Forming an implementation checks the generated forwarding functions against the declared signatures.
DIE_FUNCandSIZEare reserved vtable infrastructure names. Do not declare methods that replace them. The declared CALL name is supported specially and makes the base callable. The concrete object carries thatCALLfield too and is itself callable: reach it as@obj(21 @obj.base call), since a plainobjwould call it.
Examples
Generated implementation call
"String" use
"control" use
"interface" use
Mover: [{move: {value: Int32; result: Int32;};}] interface;
MoverImpl: @Mover [{
move: {value: Int32;} Int32 {} codeRef;
[1 +] !move
}] implement;
{base: Mover Cref;} Int32 {} [
base:;
41 base.move
] "useMover" exportFunction
{} Int32 {} [
obj: MoverImpl;
("direct: " 41 obj.base.move LF) printList
("through a Mover Cref: " obj.base useMover LF) printList
0
] "main" exportFunction
Expected Output
direct: 42
through a Mover Cref: 42
Method as a Block reading a concrete field
"String" use
"control" use
"interface" use
Adder: [{add: {amount: Int32; result: Int32;};}] interface;
AdderImpl: @Adder [{
baseValue: 10;
add: [baseValue +];
}] implement;
{} Int32 {} [
object: AdderImpl;
("result=" 41 @object.base.add LF) printList
0
] "main" exportFunction
Expected Output
result=51
Internal helper
- A stored reference produces the corresponding NIL reference form, preserving its view's constness.
- Other fields produce a new variable of the same schema; their current runtime values are not copied. Meta fields retain their Meta form.
- This operation is for generated signatures, not for cloning object data.
See also
- Function: Callable wrapper schema and callable adaptation helpers.