Compiler Built-ins
Beyond the commands Kontakt provides, CKSP ships a small set of built-in functions of its own. They are written like ordinary function calls, but the compiler resolves every one of them while translating: none of them appears as a call in the generated script. num_elements(my_array) becomes a constant, pairs(my_array) becomes a loop counter, and Zone.storage(.id) becomes the array the compiler laid out for that member.
That also explains their main restriction. A compiler built-in is not a value: it cannot be stored in a variable that holds a function, passed to a higher-order function, or redefined. It only exists in the positions described below.
-
Working With Arrays
num_elements()reports the size of an array or one of its dimensions,search()andsort()extend theirKSPcounterparts with wildcard notation. -
Driving For-Each Loops
pairs()yields index and value together,range()generates a sequence of numbers without an array to back it. -
Working With Objects
search_by()finds an object by one of its fields,storage()hands out the array a member is stored in,use_count()reports how many references an object still has. -
Conversion and Output
bool()turns a number into a boolean, andmessage()accepts more than the single argumentKSPallows.
Overview
| Built-in | Signature | Returns | Origin |
|---|---|---|---|
num_elements |
num_elements(array)num_elements(array, dimension) |
int |
extends KSP |
search |
search(array, value)search(array, value, from, to) |
int |
extends KSP |
sort |
sort(array, direction)sort(array, direction, from, to) |
void |
extends KSP |
pairs |
pairs(array) |
index/value pairs | CKSP only |
range |
range(stop)range(start, stop)range(start, stop, step) |
number sequence | CKSP only |
search_by |
search_by(array, .field, value) |
object or nil |
CKSP only |
storage |
Struct.storage(.member) |
array of the member type | CKSP only |
use_count |
use_count(pointer) |
int |
CKSP only |
bool |
bool(value) |
bool |
CKSP only |
message |
message(value, ...) |
void |
extends KSP |
num_elements
Returns the number of elements of an array. The array is passed without brackets. For a multidimensional array a second argument selects the dimension; without it, or with 0, the function reports the total number of elements of the flattened array.
Since array sizes are known at compile time, the call is usually folded into a literal and costs nothing at runtime.
Getting the Size of an Array · Size of a Specific Dimension
search and sort
Both commands exist in KSP. CKSP extends them so they also accept wildcard notation, which lets them address a single dimension of a multidimensional array.
Searching and Sorting Multidimensional Arrays
The first argument must be a reference
search and sort operate on an array in place, so their first argument has to name an array. An expression that merely evaluates to an array — a call to a function returning int[], for instance — is rejected.
pairs
Only usable as the range of a for-each loop. It yields the index alongside the value, so the loop can declare two iterators instead of one.
pairs works with everything a for-each loop accepts: arrays, multidimensional arrays, wildcard slices, initializer lists and range().
range
Generates a sequence of numbers for a for-each loop without an array to back it. stop is exclusive, start defaults to 0 and step to 1.
Negative Step Value
To count down, step has to be negative. A start greater than stop alone produces an empty range and the loop body never runs.
Iterating Over a Range of Numbers
search_by
Finds an object in an array of objects by the value of one of its fields, and returns that object — or nil if no element matches. The field is named by a member path: a leading dot followed by the member name, written without a receiver, since the array supplies the object type.
The path may reach through several objects. search_by(items, .child.id, 8) finds the Item whose child carries the id 8, and the compiler searches from the leaf back to the queried array.
The lookup is not a linear scan over the array. Every member of a struct is stored in one array holding that member's value for every instance, so CKSP can use KSP's own search on that storage and only then check whether the instance it found is part of the queried array. Duplicate field values are handled by continuing the search past each candidate.
Requirements
The first argument has to be a one-dimensional array whose elements are objects, and every segment of the path has to name a member that holds a single value per instance. An array member or a static member has no per-instance storage to search and is rejected. The searched value and the member must have matching types.
storage
CKSP gives every struct member one array that holds the value of that member for all instances, laid out back to back. pitch of every Note therefore lives in a single array. That array has no name in the source language, and storage is the way to reach it.
It is called on the struct itself, like a static method, and takes a member path naming the member whose storage is wanted:
The result is a normal array of the member's type, handed over by reference rather than copied — writing to it writes through to the instances. Its length is the number of instances the compiler reserved for the struct, which is derived from how many times the struct is constructed, not from how many instances are alive at a given moment.
Which members have storage
Only a member that holds a single value per instance is stored this way. Array and multidimensional-array members are spread over more dimensions, and static members share one value across all instances, so neither has a storage array and both are rejected. The path has to name a single member: for a member of a nested struct, ask that struct instead, as in Child.storage(.id).
storage is a reserved method name
Since Struct.storage(.member) is resolved against the member the path names, a method called storage in a struct would never be reachable. Declaring one is therefore an error.
Where the result can be used
The array only materialises at the very end of compilation, so today the result can be handed to a function parameter but not yet used as a for-each range, indexed directly, or passed to num_elements(), search() or sort(). This applies to every function returning an array and is tracked in issue #121.
use_count
Returns how many references an object currently has. CKSP manages struct memory by reference counting, so this is the value that decides whether an instance is released when a pointer goes out of scope or is deleted.
Useful when tracking down a leak from a circular reference, where the count never drops to zero on its own.
bool
Converts a value to a boolean: every non-zero number becomes true, zero becomes false.
Real numbers are converted to an integer first, so a value between 0 and 1 becomes false.
message with several arguments
KSP allows message exactly one argument. CKSP accepts any number and joins them into a single string separated by ", ", which saves writing out the concatenation.
Since the result is one string, the usual string conversion rules apply to every argument.