Skip to content
Kavachकवच

Method Chains

Also known as: method chaining fluent interface builder pattern pipeline chain dot chaining

● Intermediate5 minBefore this: Methods, LambdasSpec 1.1

Call one method on the result of the last: text.trim().lower(). Each step gives a new value for the next.

fn main() {
    const name = "  asha RAO  "
    print(name.trim().lower().replace("rao", "Rao"))
    print([5, 3, 8, 1].sort().reverse().take(2))
}

The program ran and printed:

kavach run chain-text.kav

asha Rao[8, 5]
chain-text.kav: Kavach code, then what running it prints

Read a chain left to right: trim() gives a new string, lower() works on that one, and so on. Nothing is changed in place, so name is still as it was.

One step per line

A line that starts with . carries on the line before it, so a long chain reads as a list of steps:

type Order {
    amount: Int
    paid: Bool
}

fn main() {
    const orders = [Order(amount: 300, paid: true), Order(amount: 120, paid: false), Order(amount: 80, paid: true)]
    const total = orders
        .filter(.paid)
        .map(.amount)
        .sum(a => a)
    print(total)
}

The program ran and printed:

kavach run chain-lines.kav

380
chain-lines.kav: Kavach code, then what running it prints

Chains of your own

A method that gives back its own type can be chained too. Each step here returns a new Query, made with with, so the chain builds the value one piece at a time:

type Query {
    table: String
    filters: [String] = []
    limit: Int = 100

    fn where(self, filter: String) -> Query {
        let all = self.filters
        all.push(filter)
        self with { filters: all }
    }

    fn take(self, n: Int) -> Query {
        self with { limit: n }
    }

    fn sql(self) -> String {
        "SELECT * FROM {self.table} WHERE {self.filters.join(" AND ")} LIMIT {self.limit}"
    }
}

fn main() {
    const q = Query(table: "orders")
        .where("paid")
        .where("amount > 100")
        .take(10)
    print(q.sql())
}

The program ran and printed:

kavach run chain-builder.kav

SELECT * FROM orders WHERE paid AND amount > 100 LIMIT 10
chain-builder.kav: Kavach code, then what running it prints

.paid and .amount are the dot shorthand: .paid means o => o.paid.

Go deeper the why, for readers who want it

A chain over a list doesn't build a list at every step. The compiler fuses filter, map and sum into a single loop, and a builder chain on a value nobody else holds changes it in place instead of copying it each time. You write the readable version and get the fast one.