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]
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
380Chains 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.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.