nupp.derive
nupp.derive.Debug adds a checked debug method to a record or struct. Packages publish additional providers through the same recipe API.
@derive(nupp.derive.Debug)
local record User
id: integer
name: string = "anonymous"
tags: {string} = {}
end
local user = new User(id = 1)
print(user:debug())Applying a provider is a declaration-augmentation phase, not a text macro: it cannot add imports, top-level declarations, modules, records, interfaces, or independently nameable types. nupp.derive.Debug adds debug(self): string and nupp.Debug conformance. Serialization uses explicit bindings and needs no derive.
nupp.events.Event is applied the same way and marks a record or a fixed-layout struct as an event a nupp.events source constructs and delivers.
Generated members participate in normal member lookup, generic inference, and interface checking. A written member of the same name is a compile-time conflict. Stacked @derive applications combine, but a provider cannot be requested twice. See Annotations for where @derive sits among the built-in annotations.
Debug#
debug(self): string renders a record or fixed-layout struct the way the declaration reads, so what comes back names the declaration and its fields in declaration order. The method forwards the declaration witness to the value visitor, which caches its Debug policy on first use.
(nupp.derive.Debug)
local record Point
x: integer
y: integer
end
local p = new Point(x = 3, y = -1)
print(p:debug())Point { x = 3, y = -1 }Strings are quoted, map keys are sorted by byte order so two runs agree, nested records render through their own debug, and a runtime table that reaches itself renders as <cycle>.
(nupp.derive.Debug)
local record Tag
name: string
end
(nupp.derive.Debug)
local record Post
title: string
views: integer
tags: {Tag}
scores: {[string]: integer}
end
local post = new Post(
title = "hello",
views = 12,
tags = {new Tag(name = "a"), new Tag(name = "b")},
scores = {zeta = 1, alpha = 2}
)
print(post:debug())Post { title = "hello", views = 12, tags = {Tag { name = "a" }, Tag { name = "b" }}, scores = {["alpha"] = 2, ["zeta"] = 1} }Field visibility#
A @debug field annotation decides what a field contributes. redact keeps the name and replaces the value, which is what a secret wants; skip removes the field from the output entirely.
(nupp.derive.Debug)
local record Credentials
user: string
(redact = true)
password: string
(skip = true)
cache: any
end
local c = new Credentials(user = "ada", password = "hunter2", cache = {1, 2})
print(c:debug())Credentials { user = "ada", password = <redacted> }Debug owns its selection policy. Skipped and redacted fields are never read, and a field that Debug can render need not have a JSON representation. A caller can also render an explicit binding or append to an existing Buffer:
local serde = require("nupp.serde")
local debug = require("nupp.serde.debug")
local struct Vec2
x: float
y: float
end
local binding = serde.binding(Vec2)
local output = nupp.text.newBuffer()
debug.write(binding, new Vec2(1.25, 2.5), output)
assert(output:tostring() == "Vec2 { x = 1.25, y = 2.5 }")Event#
nupp.events.Event records an event's name and representation and asks the compiler for the declaration's initializer, so a source can construct the event into storage it already holds. It generates no members; what it adds is the nupp.events.Emittable contract that every Type<E> an event source takes is bounded by.
local events = require("nupp.events")
(events.Event)
(name = "combat.Damage")
local record Damage
amount: number
source: integer
kind: string = "physical"
end
local bus: events.MessageBus<integer> = events.newMessageBus()
bus:observe(7, Damage, |event| -> print(event.kind))
bus:emit(7, Damage, amount = 10, source = 3)@event(name = "...") sets the name events.name(Damage) returns; the declaration's own name is the default. The name is what something outside the program pins, such as a debug protocol, which is why it is written rather than derived from a path that a refactor would move.
The derive admits a concrete record or a fixed-layout struct with one construction contract. It refuses a declaration with several constructors, a constructor that lets self escape or moves an owned parameter into a field, an affine field, and a generic owner, because none of those can run against storage that is reused: the next lease would find the reference, the moved obligation, or the shared identity already there.
Package providers#
A package may export a derive provider as a @comptime function. Its exact signature names the one existing interface it implements:
function M.derive(info: nupp.derive.Info): nupp.derive.Result<M.Inspect>
-- inspect info and return a closed recipe
endIn a declared module, write @comptime export function derive(...) instead of qualifying the function through a module table. Exported annotation declarations may accompany the provider and remain compile-time metadata, not runtime values.
A consumer applies the resolved exported symbol, not a runtime function value:
local inspect = require("inspect")
(inspect.derive)
local record Credentials
username: string
password: string
endApplying the provider also claims M.Inspect. An equal written is inspect.Inspect is redundant and coalesced. Interface defaults are inherited normally and associated requirements are checked normally. A provider can fill a bodyless callable requirement or declare a new function member with a closed comptime-built signature. Generic, variadic, overloaded, and effectful provider declarations are not part of the first recipe version.
Dive deeper
Debug is an exported @comptime function in src/nupp/derive.nupp. It uses the same comptime worker, immutable Info, result envelope, cache, and recipe lowering as package providers. Its @debug configuration is part of the semantic annotations visible through Info.
That is also the boundary against source generation. Comptime evaluates closed value-producing programs after normal type checking, and derives run as part of declaration checking and may attach only validated member recipes. Neither becomes a way to emit arbitrary source.
Provider inputs#
Every provider on an owner receives the same immutable pre-merge Info view. It contains the owner and interface type handles, ordered stored fields with read/write handles, semantic identities, and opaque diagnostic references. It contains no tokens, locations, comments, AST, CST, mutable compiler objects, or previous provider output. nupp.derive.claims(T, I) asks whether a nominal type writes or requests contract I, which lets mutually recursive derives plan without depending on provider execution order.
Info.name names the declaration. Info.qualifiedName combines its module and declaration path, giving providers a default identity without a source filename. Packages that persist this identity should offer an explicit override: renaming a declaration or moving it to another module changes its qualified name.
A generic owner is planned once, not per instantiation. A type parameter exposes its bound, or unknown, so providers cannot specialize for future concrete arguments.
Providers run through the bounded comptime worker. Their sealed source and reachable comptime helper closure travel in the module interface; they do not remain runtime functions. A provider failure may return nupp.derive.error(message, reference, code) to point at the owner or contributing field without observing a filename or source position. The code is optional and defaults to the generic provider diagnostic NUPP2810.
Initializers#
A provider may ask for the owner's initializer with initializer = true beside methods, statics, and data. The compiler then mints the declaration's constructor body, or its field list when it declares none, as a hidden member taking the instance first: initializer(storage, ...) fills storage the caller already holds and returns it, and new allocates and calls the same body. The runtime reaches it through nupp.derive.initializer(Type). A field-list initializer applies a field default where its argument is nil, which is the one place that can, since a positional call never passes through the checker's default filling.
The compiler refuses the request on a declaration whose body could notice the reuse: several constructors, a constructor that lets self escape or moves a takes parameter into a field, an affine field, or a generic owner, each reported as NUPP2810 on the application.
Filesystem inputs#
A provider that generates a recipe from a schema or other immutable project file reads it with nupp.derive.file:
function M.derive(info: nupp.derive.Info): nupp.derive.Result<M.Inspect>
local schema = nupp.derive.file("schemas/inspect.txt")
return nupp.derive.implement {
methods = {
inspect = nupp.derive.forward {
helper = nupp.derive.helper(M, "renderSchema"),
arguments = {nupp.derive.constant(schema)},
},
},
}
endThe path must be a string literal and remain within the consumer project root. The compiler reads it before the isolated worker starts, fingerprints its bytes with the provider input, and records it in the incremental dependency graph. Changing the file invalidates only provider consumers, and watch mode observes the canonical path and refuses to patch over changed generated state without a restart. Missing files are diagnostics.
Providers have no general host I/O, so network resources, environment variables, clocks, mutable tables, and hidden filesystem reads cannot silently enter a cache or a hot-reload guarantee.
Closed forwarding recipes#
nupp.derive.implement returns instance methods and static functions. A bare Forward fills an interface requirement and inherits its signature. A nupp.derive.member supplies a function type built with nupp.types and its parameter names, allowing a provider to add a member that is not declared by the result interface. Parameter names are non-empty and unique, and every recipe array is dense.
return nupp.derive.implement {
methods = {
inspect = nupp.derive.forward {
helper = nupp.derive.helper(M, "renderRecord"),
arguments = {
nupp.derive.constant(names),
nupp.derive.array(values),
},
},
},
}Both forms lower through forward.v1, which names one ordinary runtime helper and supplies a closed argument list:
receiver()passes the generated method receiver.argument(name)passes a named interface method parameter.entry()passes the derived type's private runtime schema entry.field(fieldInfo)directly reads one readable stored field.constant(value)embeds a bounded quotable value.witness(annotationType(argument))passes theType<T>witness named by an@refannotation argument from the owner or one of its fields.array(arguments)constructs a fresh array from argument recipes.
annotationType accepts only a kind = "type" argument taken from the provider's immutable Info. The referenced record remains typed across the comptime boundary instead of being reduced to a name string.
There are no nested calls, operators, branches, assignments, loops, arbitrary member accesses, or source fragments in a forwarding recipe. Table-shaped constants and arrays are fresh for each call, so mutation by one invocation cannot affect the next.
The first version refuses overloaded requirements, interface defaults, properties, setters, and metamethods. Those require separate versioned recipe capabilities rather than silently widening forward.v1.
Runtime helpers#
Runtime behavior stays in ordinary exported Nupp functions. Helpers are type checked at their declarations, and the generated call is checked again against the interface-owned argument and result packs, ownership, effects, and suspension contract. forward.v1 refuses generic runtime helpers; a later recipe version can admit them once symbolic helper identity and caching are specified. A helper module becomes an ordinary runtime dependency of the consumer even when the comptime provider itself would otherwise erase.
Dive deeper
Keeping behavior in the language makes arbitrary runtime control flow, optimization, effects, diagnostics, and future generic helpers available without turning them into a macro IR. A macro IR would have to grow its own version of each of those, and every one would then be a second implementation to keep agreeing with the first.
The generated wrapper is a semantic node the compiler may inline or sink when ordinary optimization proves that safe. Such optimization is not part of the provider contract, so a recipe cannot depend on it happening.
Generates checked members on a declaration while that declaration is checked.
@derive(Provider, ...) names providers on a record or struct. Each one reads an immutable semantic view of the declaration and returns a closed recipe; the compiler generates members from that recipe and checks them the way it checks written ones. This is a declaration-augmentation phase rather than a text macro. A provider adds no imports, top-level declarations, modules, or independently nameable types, and it observes no tokens, source positions, ordinary comments, mutable syntax objects, or another provider's output. It does see normalized declaration and field docblocks.
The shipped Debug provider crosses the same boundary as a package provider. Serialization uses explicit bindings instead of derive recipes.
Derive the shipped providers#
(nupp.derive.Debug)
local record Settings
host: string = "localhost"
port: integer = 8080
end
local settings = new Settings()
assert(settings:debug() == 'Settings { host = "localhost", port = 8080 }')Write a package provider#
A provider is an exported, nongeneric @comptime function whose signature names the one interface it implements. Info describes the owner, implement returns the recipe, and a consumer applies the resolved export rather than a runtime function value. Applying it also claims that interface.
local M = {}
interface M.Named
named: function(self): string
end
function M.nameValue(value: string): string
return "name=" .. value
end
function M.derive(info: nupp.derive.Info): nupp.derive.Result<M.Named>
local field = info.fields[1]
if not field or field.name ~= "name" then
return nupp.derive.error("Named needs a first field named name", info.reference)
end
return nupp.derive.implement{
methods = {
named = nupp.derive.forward{
helper = nupp.derive.helper(M, "nameValue"),
arguments = {nupp.derive.field(field)},
},
},
}
end
(M.derive)
record M.User
name: string
end
local user = new M.User(name = "ada")
assert(user:named() == "name=ada")
return MRecipe vocabulary#
The interface owns every generated signature, so a recipe chooses only which runtime function stands behind a requirement and which values reach it. forward names one ordinary exported Nupp function and a closed argument list built from receiver, argument, field, constant, and array. There are no nested calls, operators, branches, loops, assignments, or provider-chosen signatures, so behavior stays in ordinary type-checked Nupp rather than in a macro IR, and the generated call is checked against the helper's declaration the way any other call is.
forward.v1 fills only bodyless, unoverloaded callable requirements, and cannot replace an interface default. A provider that refuses a declaration returns error rather than raising.
Providers run inside the bounded comptime worker, once per owner rather than once per generic instantiation, and a recipe is memoized on the Info fingerprint. claims asks whether a type already writes or requests an interface, which lets mutually recursive derives plan without depending on evaluation order.
Module contents
Types
| Type | Kind | Description |
|---|---|---|
Argument | record | A value a generated call passes. |
DebugOptions | interface | The checked shape of @debug, written on a field. |
Entry | record | |
EventOptions | interface | The checked shape of @event, written on a declaration deriving nupp.events.Event. |
Field | record | A written stored field in the immutable derive input projection. |
Forward | record | A requirement's implementation, from forward, to be placed in implement under the name of the requirement it fills. |
Info | record | The immutable semantic view passed to an @comptime function provider. |
Member | record | A generated member with a comptime-built function signature and forward recipe. |
Provider | record | A comptime-only provider symbol accepted by @derive. |
Reference | record | An opaque reference which a provider may attach to a diagnostic. |
Result | record | What a provider returns: the recipe implementing interface I. |
RuntimeHelper | record | An ordinary exported Nupp function a generated member calls, from helper. |
Functions
| Function | Kind | Description |
|---|---|---|
annotationType | function | Resolves a @ref annotation argument to its transported type handle. |
argument | function | Passes a parameter of the generated method, under the name the interface requirement declares for it. |
array | function | Builds a fresh array from argument recipes, once per call. |
claims | function | Asks whether a type writes or requests an interface. |
constant | function | Embeds a bounded quotable value. |
Debug | comptime function | Generates debug(self): string and nupp.Debug conformance for a record or struct. |
debug | function | Renders a declaration through its Debug binding. |
install | function | Installs the runtime called by generated derive members. |
entry | function | Passes the record's registered derive entry. |
error | function | Refuses the declaration with a diagnostic instead of returning a recipe. |
field | function | Reads a stored field of the receiver directly. |
file | function | Reads an immutable filesystem input admitted to this provider invocation. |
forward | function | Implements a requirement by calling a runtime helper. |
helper | function | Names an ordinary exported Nupp function to forward to. |
implement | function | Returns forwarding implementations. |
member | function | Declares a generated member's function signature and forwarding recipe. |
receiver | function | Passes the generated method's receiver. |
witness | function | Passes a named record's first-class Type |
Types#
Argumentrecord#
record ArgumentA value a generated call passes.
Built by receiver, entry, argument, field, constant, witness, or array. The compiler owns it: a provider may hold one and place it in an argument list, and nothing else.
DebugOptionsinterface#
interface DebugOptions ...The checked shape of @debug, written on a field.
Entryrecord#
record derive.Entry ...mtfield#
mt: anyEventOptionsinterface#
interface EventOptions ...The checked shape of @event, written on a declaration deriving nupp.events.Event.
Members
| Name | Kind | Description |
|---|---|---|
name | field | The name the event registers under. |
Fieldrecord#
record Field ...A written stored field in the immutable derive input projection.
Fields arrive in declaration order. A generated member never reaches one by name; pass this value to field to read it.
Members
| Name | Kind | Description |
|---|---|---|
name | field | The name as written. |
documentation | field | The field's --- documentation text, with markers and tags removed. |
readable | field | Whether the field can be read, and so whether field admits it. |
writable | field | Whether the field can be written. |
readType | field | A transported handle for the read type, or nil for a write-only field. |
writeType | field | A transported handle for the write type, or nil for a read-only field. |
hasDefault | field | Whether omission during construction supplies a declaration-owned default. |
defaultValue | field | The source-free constant default value. |
annotations | field | The field's typed annotations in source order, @debug among them. |
reference | field | Points this provider's error at this field. |
documentationfield#
documentation: string?The field's --- documentation text, with markers and tags removed.
readablefield#
readable: booleanWhether the field can be read, and so whether field admits it.
readTypefield#
readType: any?A transported handle for the read type, or nil for a write-only field.
writeTypefield#
writeType: any?A transported handle for the write type, or nil for a read-only field.
hasDefaultfield#
hasDefault: booleanWhether omission during construction supplies a declaration-owned default.
defaultValuefield#
defaultValue: anyThe source-free constant default value. Read only when hasDefault is true.
annotationsfield#
annotations: {nupp.reflect.Annotation}The field's typed annotations in source order, @debug among them.
Forwardrecord#
record ForwardA requirement's implementation, from forward, to be placed in implement under the name of the requirement it fills.
Inforecord#
record Info ...The immutable semantic view passed to an @comptime function provider.
An Info describes an owner for a provider, and is built before any provider's output is merged, so two providers on the same declaration see the same thing whichever order they run in. A generic owner is projected once rather than per instantiation, and a type parameter exposes its bound, or unknown, so a provider cannot specialize for arguments a later instantiation supplies.
Members
| Name | Kind | Description |
|---|---|---|
schema | field | The projection's schema version, currently 2. |
kind | field | What the owner was declared as: record, struct, or interface. |
name | field | The owner's declared name. |
qualifiedName | field | The declaration's module-qualified name, independent of filesystem paths. |
visibility | field | How the declaration is bound: local, module, global, or nested. |
documentation | field | The declaration's --- documentation text, with markers and tags removed. |
providerIdentity | field | The stable identity of the provider being run. |
ownerIdentity | field | The stable identity of the owning declaration. |
ownerType | field | A transported handle for the owner's type, accepted by claims. |
interfaceType | field | A transported handle for the one interface this provider implements. |
fields | field | The written stored fields, in declaration order. |
annotations | field | The owner's own typed annotations, in source order. |
hasConstructor | field | Whether the declaration writes a constructor. |
reference | field | Points this provider's error at the declaration as a whole. |
fingerprint | field | A digest of everything above. |
qualifiedNamefield#
qualifiedName: stringThe declaration's module-qualified name, independent of filesystem paths.
visibilityfield#
visibility: stringHow the declaration is bound: local, module, global, or nested.
documentationfield#
documentation: string?The declaration's --- documentation text, with markers and tags removed.
providerIdentityfield#
providerIdentity: stringThe stable identity of the provider being run.
ownerTypefield#
ownerType: anyA transported handle for the owner's type, accepted by claims.
interfaceTypefield#
interfaceType: anyA transported handle for the one interface this provider implements.
annotationsfield#
annotations: {nupp.reflect.Annotation}The owner's own typed annotations, in source order.
hasConstructorfield#
hasConstructor: booleanWhether the declaration writes a constructor.
referencefield#
reference: ReferencePoints this provider's error at the declaration as a whole.
fingerprintfield#
fingerprint: stringA digest of everything above. Two owners with one fingerprint share one evaluation, so a provider must decide from Info and nothing else.
Memberrecord#
record MemberA generated member with a comptime-built function signature and forward recipe. Use this when the provider declares a member that is not already an interface requirement.
Providerrecord#
record ProviderA comptime-only provider symbol accepted by @derive.
A shipped provider is one of the three values below; a package provider is the @comptime function a module exports. Neither survives into the program.
Referencerecord#
record ReferenceAn opaque reference which a provider may attach to a diagnostic.
Obtained from Info.reference for the declaration or Field.reference for one field, and accepted only by error. It carries no filename, line, or column: a provider says which part of the declaration is at fault and the compiler decides where to point.
Resultrecord#
record Result<I>What a provider returns: the recipe implementing interface I.
I is the interface the provider implements, or any when every generated member supplies its own signature. Writing an interface in the return type is how @derive knows which contract applying the provider claims. Produce one with implement, or refuse the declaration with error. The compiler owns it and there is nothing on it to read: what it carries crosses the comptime boundary as a versioned recipe the compiler validates.
Type parameters
| Name | Description |
|---|---|
I | the interface this provider implements, or |
RuntimeHelperrecord#
record RuntimeHelperAn ordinary exported Nupp function a generated member calls, from helper.
The module owning it becomes a runtime dependency of the consumer, even when the comptime provider itself erases.
Functions#
annotationTypefunction#
local annotationType: function(argument: nupp.reflect.AnnotationArgument): anyResolves a @ref annotation argument to its transported type handle.
The argument must come from Info.annotations or one of its fields. The returned handle can be inspected with nupp.types and passed to witness.
Arguments
| Name | Type | Description |
|---|---|---|
argument | nupp.reflect.AnnotationArgument | a reflected annotation argument whose kind is |
Returns
| Type | Description |
|---|---|
any | the referenced type handle |
argumentfunction#
Passes a parameter of the generated method, under the name the interface requirement declares for it.
Arguments
| Name | Type | Description |
|---|---|---|
name | string | the parameter's declared name |
Returns
| Type | Description |
|---|---|
Argument | the argument recipe |
arrayfunction#
Builds a fresh array from argument recipes, once per call.
Arguments
| Name | Type | Description |
|---|---|---|
arguments | {Argument} | the element recipes, in order |
Returns
| Type | Description |
|---|---|
Argument | the argument recipe |
claimsfunction#
local claims: function(subject: any, interface: any): booleanAsks whether a type writes or requests an interface.
The answer does not depend on whether that type's own providers have run, so mutually recursive derives can plan against one another.
Arguments
| Name | Type | Description |
|---|---|---|
subject | any | a type handle, such as a |
interface | any | a type handle, such as |
Returns
| Type | Description |
|---|---|
boolean | whether |
constantfunction#
Embeds a bounded quotable value.
A table-shaped constant is rebuilt for every call, so mutation by one invocation cannot reach the next.
Arguments
| Name | Type | Description |
|---|---|---|
value | any | the value to embed |
Returns
| Type | Description |
|---|---|
Argument | the argument recipe |
derive.Debugcomptime function#
Generates debug(self): string and nupp.Debug conformance for a record or struct. The method lazily prepares a schema-driven declaration-order formatter and shares its schema recipe with Serde when both are derived.
@debug(redact = true) keeps a field's name and hides its value, which is what a secret wants; @debug(skip = true) removes the field from the output entirely.
(nupp.derive.Debug)
local record Credentials
user: string
(redact = true)
password: string
end
local credentials = new Credentials(user = "ada", password = "hunter2")
assert(credentials:debug() == 'Credentials { user = "ada", password = <redacted> }')Arguments
| Name | Type | Description |
|---|---|---|
info | nupp.derive.Info |
Returns
| Type | Description |
|---|---|
nupp.derive.Result<nupp.Debug> |
derive.debugfunction#
Renders a declaration through its Debug binding.
Arguments
| Name | Type | Description |
|---|---|---|
target | unknown | the declaration witness |
borrows value | unknown | the borrowed value to render |
Returns
| Type | Description |
|---|---|
string |
derive.installfunction#
function derive.install(namespace: any): nilInstalls the runtime called by generated derive members.
Arguments
| Name | Type | Description |
|---|---|---|
namespace | any | the program's |
Returns
| Type | Description |
|---|---|
nil |
entryfunction#
Passes the record's registered derive entry.
Returns
| Type | Description |
|---|---|
Argument | the argument recipe |
errorfunction#
Refuses the declaration with a diagnostic instead of returning a recipe.
The reference decides what the diagnostic points at: Info.reference for the declaration, or the Field.reference of the field that made the recipe impossible. Returning this is how a provider fails; raising is a provider fault.
Arguments
| Name | Type | Description |
|---|---|---|
message | string | what the consumer is told |
reference | Reference? | which part of the declaration is at fault |
code | string? | the diagnostic code, defaulting to |
Returns
| Type | Description |
|---|---|
any | the refusal, as this provider's |
fieldfunction#
Reads a stored field of the receiver directly. The field must be readable.
Arguments
| Name | Type | Description |
|---|---|---|
field | Field | one of |
Returns
| Type | Description |
|---|---|
Argument | the argument recipe |
filefunction#
Reads an immutable filesystem input admitted to this provider invocation.
The path must be a string literal in the provider's checked source. It resolves from the consumer project root, becomes an incremental query dependency, and is included in the provider recipe fingerprint. Watch mode therefore observes the file and rechecks only modules that consume the provider.
Arguments
| Name | Type | Description |
|---|---|---|
path | string | project-relative path written as a literal |
Returns
| Type | Description |
|---|---|
string | the file's bytes |
forwardfunction#
Implements a requirement by calling a runtime helper.
helper names the function and arguments is the closed list it receives, in order. The interface owns the resulting signature, and the generated call is checked against the helper's declaration for types, ownership, effects, and its suspension contract.
Arguments
| Name | Type | Description |
|---|---|---|
specification | any | a table with |
Returns
| Type | Description |
|---|---|
Forward | the implementation, to place in |
helperfunction#
local helper: function(module: any, name: string): RuntimeHelperNames an ordinary exported Nupp function to forward to.
Runtime behavior stays in the language: helpers are checked at their own declarations, and a generic helper is refused by forward.v1.
Arguments
| Name | Type | Description |
|---|---|---|
module | any | the module value holding the function |
name | string | the name it is exported under |
Returns
| Type | Description |
|---|---|
RuntimeHelper | the helper handle |
implementfunction#
local implement: function(specification: any): anyReturns forwarding implementations. methods fills instance members and statics fills static members.
Both are keyed by member name. A Forward fills a bodyless, unoverloaded callable requirement on the provider's interface; a Member supplies a new member's function signature and forwarding recipe. Generating a member that another provider on the same owner already generates is refused.
Arguments
| Name | Type | Description |
|---|---|---|
specification | any | a table with optional |
Returns
| Type | Description |
|---|---|
any | the recipe, as this provider's |
memberfunction#
Declares a generated member's function signature and forwarding recipe. Parameter names are non-empty and unique.
a forward recipe
Arguments
| Name | Type | Description |
|---|---|---|
specification | any | a table with |
Returns
| Type | Description |
|---|---|
Member | the member recipe, to place in |
receiverfunction#
Passes the generated method's receiver.
Returns
| Type | Description |
|---|---|
Argument | the argument recipe |
witnessfunction#
Passes a named record's first-class Type<T> witness to the runtime helper.
Arguments
| Name | Type | Description |
|---|---|---|
subject | any | a transported nominal type handle |
Returns
| Type | Description |
|---|---|
Argument | the argument recipe |