rokdocs
v0.1

4.9. Methods

This document defines in detail the parameters and calling conventions of methods defined in impl. It is part of the function specification and focuses on the differences between methods and free functions.

4.9.1. Where methods are defined

Methods are defined inside an impl block.

impl Point {
    fn origin() -> Point { Point { x: 0.0f64, y: 0.0f64 } }
    fn distance(self, other: Point) -> f64 { ... }
    fn translate(ref self, dx: f64, dy: f64) {
        self.x = self.x + dx;
        self.y = self.y + dy;
    }
}

4.9.2. Kinds of methods by the form of the first parameter

Static methods: no self

impl Point {
    fn origin() -> Point { ... }              // static
    fn from_polar(r: f64, theta: f64) -> Point { ... }
}

let p = Point::origin();                       // Type::method() call
let q = Point::from_polar(1.0f64, 0.0f64);

A static method is a function whose first parameter is neither self nor ref self. It is called as Type::method(args), which is static item access through type paths.

Instance methods: self

impl Point {
    fn distance(self, other: Point) -> f64 { ... }
    fn norm(self) -> f64 { ... }
}

let d = p.distance(q);                         // instance.method() call
let n = p.norm();

In this form the first parameter is self. self denotes the instance's value (a copy for a struct, 2.3.8), and the body accesses fields with self.field. It is called as instance.method(args).

Instance methods: ref self

impl Point {
    fn translate(ref self, dx: f64, dy: f64) {
        self.x = self.x + dx;
        self.y = self.y + dy;
    }

    fn replace_with(ref self, other: Point) {
        self = other;                          // the caller's variable becomes other
    }
}

let p = Point { x: 1.0, y: 2.0 };
p.translate(5.0f64, 0.0f64);                   // called without explicit ref
p.replace_with(other);                         // likewise

In this form the first parameter is ref self. Inside the body, self and its fields may be assigned, and the result is written back to the caller's variable (see the ref keyword). The caller does not write ref, because method call receivers are handled automatically.

4.9.3. Two uses of the self Keyword

impl Point {
    fn distance(self, other: Point) -> f64 {
        let dx = self.x - other.x;             // uses the instance self
        let dy = self.y - other.y;
        (dx * dx + dy * dy).sqrt()
    }
}

self (keywords) is used in two positions. In parameter position it is the parameter that receives the instance; inside the body it is the identifier referring to that parameter.

self in parameter position is written without a type. Its type is automatically Self, the target type of the current impl.

4.9.4. The Self keyword: type position

Self (keywords, capitalized) is a type name referring to the target type of the current impl.

impl Point {
    fn new(x: f64, y: f64) -> Self {           // Self == Point
        Self { x, y }                          // Self can also construct instances
    }
}

The two must be clearly distinguished: lowercase self is used as a parameter and instance identifier; uppercase Self is used as a type name.

4.9.5. Automatic ref for method call receivers

For a ref self method, ref is applied automatically even though the caller does not write it at the call.

impl Counter {
    fn increment(ref self) { self.count = self.count + 1; }
}

let c = Counter { count: 0 };
c.increment();                                 // no explicit 'ref'

This is an exception to the ordinary function call rule of the ref keyword (explicit ref required). The reasons: method call syntax x.method() is itself the receiver dispatch mechanism, and the call form is the same whether the receiver is self or ref self. An additional explicit ref would be visual noise.

This is consistent with the method call conventions of Rust, C# and Swift. However, when calling the same method by path, the receiver is an ordinary argument, so ref is written (Counter::increment(ref c), 4.7.3).

4.9.6. Call forms of free functions and methods

FormCall
Free functionfunction_name(args)
Static methodType::method(args)
Instance methodinstance.method(args)

The call form clearly distinguishes what a function means.

Name conflicts between traits

When x.method() has multiple candidates, one is chosen in this order:

  1. Methods of an inherent impl take precedence over trait methods.
  2. Among trait methods, a trait defined by the current package or explicitly used takes precedence over a trait visible only through the implicit use rok::core::**. The current package is the actual package in which the call is written. A dependency package's trait does not take precedence over core's traits unless it is used.
  3. If there is still more than one candidate, it is an ambiguity error, and the diagnostic suggests writing it as Trait::method(x).
use pkg::geom::Union;              // user trait - union method
a.union(b);                        // pkg::geom::Union takes precedence over core's Union
rok::core::ops::Union::union(a, b) // explicit to use the core one

4.9.7. Calling other methods inside a method

impl Point {
    fn distance(self, other: Point) -> f64 { ... }

    fn distance_squared(self, other: Point) -> f64 {
        let d = self.distance(other);          // another method of the same instance
        d * d
    }
}

Other methods of the same instance may be called as self.method(). The same rules as ordinary instance calls apply.

4.9.8. Method visibility

Method visibility follows the module-private default defined in impl.

impl Account {
    pub fn balance(self) -> f64 { ... }        // public
        fn _internal(self) { ... }              // module-private
}

The exact rules for visibility levels are defined in visibility.

4.9.9. Freedom in method signatures

Method parameters, returns and bodies follow the ordinary function rules of Parameters and Return. Specifically, default values, named arguments, variadics and spreads may be used freely in methods. Divergent methods, whose body always exits through throw or an infinite loop, are also possible, and generic methods may use both the generic parameters of the impl block and the method's own generics.

impl<T> List<T> {
    fn map<U>(self, f: fn(T) -> U) -> List<U> { ... }
}

A method's own generics follow the function name (fn map<U>(...)). In a trait impl, a method parameter without a type takes the type the trait declares at that position (trait parameters and associated types substituted), not an implicit type parameter.

4.9.10. Summary of self in methods

First parameterMeaningAt the callCan self be reassigned in the body?
(none)static methodType::method()-
selfinstance method (value)instance.method()no (local only)
ref selfinstance method (ref)instance.method() (ref automatic)yes (reflected in the caller)

These three forms are the only kinds of methods.

Edit this page on GitHub