Methods

An extend block adds functions to a type. A function in it whose first parameter is named self is a method, called on a value with .: counter.Advance(). A function without self is a static function of the type, called through its name with ::: Counter::Zero(5).

extension = "extend" type [ ":" interface ] "{" { function } "}"
receiver  = "self" ":" ( type | "&" type | "&" "var" type )
struct Counter {
    count: int;
    step: int;
}

extend Counter {
    func Zero(step: int) -> Counter {
        return Counter { count: 0, step: step };
    }

    func Value(self: &Counter) -> int {
        return self.count;
    }

    func Advance(self: &var Counter) {
        self.count += self.step;
    }

    func Advanced(self: Counter) -> Counter {
        var next = self;
        next.Advance();
        return next;
    }
}

func Main() -> int {
    var counter = Counter::Zero(5);
    counter.Advance();
    counter.Advance();
    let ahead = counter.Advanced();
    PrintLine("{} {}", counter.Value(), ahead.Value());   // 10 15
    return 0;
}

A type may have any number of extend blocks, in any file of its package. The type's fields stay in the struct declaration; an extend block holds only functions. extend works for every named type — structs, enums, variants, unions — and for built-in types, as Extensions shows.

Receivers

The receiver is always named self, always comes first, and has its type written out like any other parameter. The type is the extended type, or a reference to it, and decides what the method may do:

ReceiverThe method getsMay change the caller's valueCallable on
self: &Counterthe caller's value, to readnoany Counter
self: &var Counterthe caller's value, to changeyesa var Counter
self: Countera copy, read-onlynoany Counter

A &T receiver is the usual choice for a method that only reads; &var T for one that changes the value in place; T for small values such as numbers and enum cases, or for a method that wants its own copy to work on, as Advanced does.

Inside a method, fields are always reached through self. There is no implicit scope: a bare count is an unknown name.

A receiver is read-only like every parameter, and a &T receiver cannot be written through:

error: cannot modify immutable receiver 'self'
  help: take the receiver as 'self: &var Counter' to change the caller's value
error: cannot modify data through immutable reference '&Counter'

Calling methods

The value before the dot becomes self. It is borrowed when the receiver is a reference and copied when it is a value; the call site writes nothing extra in either case. The remaining arguments go in the parentheses.

A method with a &var T receiver needs a value it can write to:

let fixed = Counter::Zero(1);
fixed.Value();     // fine
fixed.Advance();   // error
error: cannot call 'Advance' on immutable 'fixed'
  note: 'Advance' declares a writable receiver '&var Counter'
  help: declare 'fixed' with 'var' to make it mutable

A method that reads may also be called on a value that has no name, such as a literal: Counter { count: 9, step: 1 }.Value().

KindDeclaredCalled as
Methodfunc Value(self: &Counter) -> intcounter.Value()
Static functionfunc Zero(step: int) -> CounterCounter::Zero(5)
Constructorfunc Counter(step: int) -> CounterCounter(5)

A method is reached only through a value. It is not in scope as a free function, and it cannot be called through the type path:

error: name 'Value' is not defined in this scope
error: call to 'Counter::Value' expects 0 arguments, but 1 was provided

Each type has its own methods, so Rectangle and Circle may both have an Area without clashing; the type of the value before the dot decides which runs. Methods of one type overload like functions, by their parameters after self; see Overloading.

Rules and errors

MistakeError
The receiver given another name, this: &Counterit is an ordinary parameter; counter.Value() then expects 1 argument, but 0 were provided
self after another parameterreceiver 'self' must be the first parameter of method 'Value'
self without a type, Value(self)expected ':' and the receiver type after 'self' before ')'
A receiver of another typereceiver type '&Other' does not name the extended type 'Counter'
A method named without parentheses, counter.Valuestruct 'Counter' has no field 'Value'

What else goes in extend

DeclarationPage
func T(...) -> TConstructors
func ~T(self: &var T)Destructors
func +(self: T, other: T) -> T and the other operatorsOperators
func [](self: &T, index: uint) -> EIndexers
extend T : Interface { … }Interfaces

A generic type's extend block names its type parameters, extend Pair<T> { … }, and a method may have type parameters of its own; see Generic methods. pub on each function makes it visible to other packages — pub on the struct does not reach its methods, and calling one that lacks it from another package is method 'Secret' is private to package 'Shapes'.

See also