Verbs and participles
A verb changes its receiver in place and is a var fn, and its participle answers a changed copy instead, so calling the verb through a const path names the participle in its error.
Diese Seite gibt es noch nicht auf Deutsch, deshalb steht sie hier auf Englisch. Zur englischen Seite
Two methods often come in a pair: one that changes a value in place and one that answers a changed copy instead. The standard library names them so the difference is visible from the name alone, and the compiler leans on the same naming when it explains why a call was rejected.
Example#
type Counter {
var value: Int = 0
var fn increment() {
value = value + 1
}
fn incremented(): Counter {
copy(value: value + 1)
}
}
var counter = Counter()
counter.increment()
const next = counter.incremented()
print "{counter.value} {next.value}"Syntax#
var fn <verb>(<parameters>) // Changes in place, answers nothing
fn <participle>(<parameters>): Self // Answers the changed copy, leaves the receiver aloneRules#
A verb changes its receiver in place and is a
var fn.incrementneeds avarpath to run, exactly like any other method that is avar fn.A participle answers a changed copy and is an ordinary
fn.incrementednever needs avarpath, becausecounteritself is untouched -copyalready does the work of building the new value.A participle answers
Self. That is the rule and not a convention:list.appended(x),list.removedAt(index),list.reversed()andlist.sorted(by:)all answer a list of the same kind, so a participle can be chained and aconstbinding needs no conversion after it. Where a supertrait declares the same word for something wider -Iterate.sortedis a lazy stage answeringIterate<Item>- the collection that knows better overrides it, and the more derived declaration is the one a call reaches.const numbers = [3, 1, 2] const ordered: List<Int> = numbers.sorted({ _ }) print ordered print numbersWhere the verb answers a value the copy could not get back, there is no participle.
list.removedAt(index)answersSelf, becauselist[index]is there to be read first.stack.pop()andqueue.dequeue()answer the item they take, and a participle would have to answer the pair(Item, Self)?- so a stack and a queue have none, and avarcopy keeps the old version instead.const stack = Stack.of 1, 2, 3 var rest = stack if const Some(top) = rest.pop() { print "{top} {rest.length()} {stack.length()}" }Calling a verb through a
constpath is an error that names the participle, when the compiler can build one for the method's name. This is the one message of the language that suggests the member a caller probably wanted.Kompiliert nichttype Counter { var value: Int = 0 var fn increment() { value = value + 1 } } const frozen = Counter() frozen.increment() // error: `increment` needs a `var`A noun never changes anything.
unionandintersectionread as operations, not as verbs, so neither one is avar fn- a name that could be misread as a verb is a naming mistake independent of what the member actually does.A verb is picked so that its participle is a different word. The standard library avoids
put,cutandresetas mutator names, because none of them has a distinct participle to pair with;setpairs withupdatedinstead of a participle of its own.
What this is not#
A missing var is not fixed by adding () or a different call style. The error is about the path the receiver
came through, not about how the call is written - frozen.increment() and frozen.increment fail for the same
reason, because frozen itself is the problem.
var counter = Counter()
counter.increment()
print counter.valuetype Counter {
var value: Int = 0
var fn increment() {
value = value + 1
}
}
fn tick(counter: Counter) {
counter.increment()
}
// error: `increment` needs a `var`Related#
- Declaring a type - where a verb and its participle first appear,
translate/translated. - Mutation and var paths - what makes a path a
varpath in the first place. - Methods and
static fns -staticagainst a receiver, the more basic distinction.