Skip to main content

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 uppercases s.
  • 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"
note

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, ",").