Definition#
To <function name> with a <type> called <param1> and a <type> called <param2>. Return a <type>, <expression>.
No-parameter functions are also valid:
To 'show version'.
Print "1.0.0".
To ping.
Print "pong".
Examples:
To 'add numbers' with a number called x and a number called y. Return a number, the x add y.
To 'check divisibility' of a number called divisor and a number called dividend. Return a boolean, the divisor modulo the dividend is 0.
Rules:
- Function name is a bare single word (
add) or a single-quoted multi-word name ('add numbers') - Parameters are optional. If present, introduce them with
withorof(both work identically) - Parameters use
a <type> called <name>syntax (bare if single-word,'single-quoted'if it contains spaces) - Multiple parameters joined with
and - Return type follows
Return a <type>,
Function Scope#
- Variables declared at top level are global and can be used inside functions — including inside a function written above the declaration, because the body runs when it is called, and it reads the global as its declared type either way. A function that runs before the declaration has been reached reads the type's empty value —
"",[],{}, an empty buffer,0,0.0,false— never the value the declaration will go on to store. Top-level code has no such licence: see Declaration Order. - Variables declared inside a function are local to that function and are not available at top level.
- Referencing an unknown variable inside a function is a compile-time error.
- Assigning to a top-level variable inside a function (
Set g to .../the g is ...) mutates the global itself, so the new value is visible after the call returns and to every other function. - Declaring a variable inside a function shadows a top-level variable of the same name (
a number called g is 5.inside a function creates a localg); the global is left untouched. Recursion still gets a fresh set of locals per call. This applies tovaluetoo: its payload and runtime type tag are stored as a pair, in whichever storage (function-local, or the top-level global's own pair of storage locations) that particularvalueuses, so a mutation inside one function is never visible to another unless it is genuinely the same global.
Parameter and Local Types#
Parameters may use any of the 11 expressible types — number, float, text, boolean, list, map, buffer, file, time, timer, value — and a typed parameter supports the same properties and operations as a top-level variable of that type. The same 11 types are also legal as a declared Return a <type>, return type — parameters and returns share one vocabulary, not two. A parameter (or return type) may also be value, the dynamic type whose runtime tag travels with its payload across the call (a map rides this as payload + tag 5); see Dynamic Values (value) below.
To 'contains token' of a buffer called hay and a text called devname.
a buffer called needle is " {devname}\n".
a number called H is hay's size.
a number called b is byte 1 of hay.
...
Key points:
- Buffer parameters support
's size/'s empty/'s fulland byte access; list parameters support's length/element access; map parameters support's length/'s empty/'s keys/'s valuesand keyed access, and print as a whole map (print holder.,"{holder}"); file parameters support file properties. - A
bufferparameter is the caller's buffer, and stays the caller's buffer across a growth: anappend, aresize, or a byte written past the current capacity moves the block, and the caller's variable follows it there. Declaring a buffer of the same name inside the function names a different buffer from that point on and leaves the caller's alone;Set <parameter> to ...is not a rebinding — on a buffer it copies bytes into the buffer the parameter already names, so the caller sees the new bytes. - Buffers declared inside a function body work with every initializer form, including format strings (
is " {devname}\n"). - A function call's declared return type is tracked through assignment: reassigning an existing variable from a call (
the label is classify of n.) preserves the correct type.
A collection parameter is the caller's collection#
A list or map parameter names the caller's collection, not a copy of it. Whatever the function does to it - setting an element, appending, inserting a key, growing it past whatever size it started at - is what the caller's variable holds when the call returns, however many calls deep the collection was passed:
To 'add one to' with a list called items.
append "x" to items.
a list called xs is ["a"].
'add one to' of xs.
'add one to' of xs.
Print xs's length. (prints: 3)
This is the opposite of a thing parameter, which is a copy (see Things below): a thing has no reference to share, and a collection is nothing but one. Only a variable can be written back to - a collection built at the call itself ('the size of' of [1, 2, 3]) has nowhere to return growth to, so the function may read and grow it freely but the growth goes nowhere once the call ends.
A .so with a list or map parameter and the programs that see it must be built by the same version of Vox.
Function Calls#
In expressions, use the function name followed by of, to, with, or on and arguments:
'add numbers' of 3 and 5
'check divisibility' of the number and 6
calculate with x and y
Rules:
- Function name is a bare single word (
calculate) or a single-quoted multi-word name ('add numbers') - For calls with arguments, use
of,to,with, oron - Multiple arguments separated by
and
Calls with no arguments can be written directly:
'show version'.
ping.
Calling as Statement#
Print 'add numbers' of x and y.
Reading a result#
Return a <type>, is optional in the grammar, but it decides where the result may be read. A declared return type travels to every call site, so the result can be printed, interpolated, stored in a list or map slot, or put in a value — each of those reads it back as what it is.
A result with no declared return type has nothing to be read as, and the compiler will not guess: it is accepted only where the position itself supplies the type, and refused where nothing does.
To 'opaque label'. Return "hi".
a text called saved is 'opaque label'. (fine — the declaration says text)
print saved. (prints: hi)
print 'opaque label'. (compile error: no declared return type)
Positions that supply a type: a declared variable's declaration, a later assignment to one, and an argument landing on a declared parameter. Every other position — print <call>, a {...} interpolation, append, a list literal slot, set element, a map value, a value declaration — needs the return type declared. See Mixed-Type Lists.