Pipes
A pipe is a self-operator that transforms a value in place. The colon
notation receiver:name(args) looks up the function name in the pipe table
and calls it with the receiver injected as the first argument:
receiver:name(args) == receiver = name(receiver, args)
Two important properties:
- The result is assigned back to the receiver, so pipes read naturally as
in-place transformations:
s:trim():upper()trims then uppercasess. - The return type must match the receiver's type. A pipe that returns a
different type raises a
TYPE_ERROR.
Pipes resolve through the pipe table and the global/std scope, never
through the receiver's own members — a function stored in an object is called
with dot (obj.fn(...), where the receiver is not passed).
var s = " hello "
s:trim():upper() // s -> "HELLO"
var arr = [3, 1, 2]
arr:sort():reverse() // arr -> [3, 2, 1]
var obj = {a: 1}
obj:merge({b: 2}) // obj -> {a: 1, b: 2}
print("abc":upper()) // error: literals cannot be receivers
The pipe builtins
pipe(name, fn) registers a callable name in the pipe table. From then on,
receiver:name(args) calls fn(receiver, args).
pipe_remove(name) unregisters it and returns true if it was removed:
pipe("double", fn(n) { return n * 2 })
var x = 21
x:double() // x -> 42
print(pipe_remove("double")) // true
// x:double() // error: unknown pipe 'double'
Initially available pipes
The built-in pipe table is seeded with a curated set of standard library functions:
Strings
upper lower trim trim_left trim_right
substr replace replace_first repeat pad_left pad_right
Arrays (from std.sort and std.seq)
sort sort_by shuffle unique flatten slice concat fill
map filter find_all zip
take drop chunk enumerate
set_union set_intersect set_difference
Objects
merge
Dispatch pipes — work on more than one receiver type:
insert // strings, arrays, objects
erase // strings, arrays, objects
reverse // strings, arrays
var s = "hello"
s:insert(1, "X") // s -> "hXello"
var n = [1, 2, 3]
n:erase(1) // n -> [1, 3]
var w = "abc"
w:reverse() // w -> "cba"
Not every std.* function is available as a pipe — only the ones seeded above
(plus anything you register). To call any other library function use the dot
form, e.g. std.string.split(s, ",").