Methods

A function declared inside a struct or an enum is a method of that type. A method whose first parameter is self, written without a type, is called on a value of the type, which self holds; one without self is called on the type itself:

struct Point do
    int x
    int y

    func length(self) f64 do
        return sqrt(f64(self.x * self.x + self.y * self.y))
    end

    func shift(self, int dx) do
        self.x += dx
    end

    func origin() Point do
        return Point(0, 0)
    end
end

Point p = Point(3, 4)
print(p.length())          // 5.000000
p.shift(1)
Point o = Point.origin()

Enums have methods the same way, after or between their members, as in func area(self) f64 do match self do ... end end, and their functions are called as Shape.unit(). A member's name comes first, so a function of an enum needs a name no member has.

A method can also be declared outside its type, by writing the type before its name. This adds methods to built-in types, to arrays and maps, and to types from other modules:

func str.shout(self) str do
    return upper(self) + "!"
end

func int[].total(self) int do
    int sum = 0
    for n in self do
        sum += n
    end
    return sum
end

print("hey".shout(), [1, 2, 3].total())   // HEY! 6

A method of a generic struct or enum uses its type parameters, and may have type parameters of its own. Declared outside the type, the names in the type's brackets that are not types are its type parameters, as T in func Stack[T].size(self) int. Stack[int].of(5) writes the type arguments of a function of the type; otherwise they come from the arguments.

Methods belong to their type wherever it is used: a type has one method of each name, which no field of a struct may share, and a method needs exactly the type it is declared on, so func int.half(self) is not a method of an i64. When a struct has a field that holds a function, value.name(...) calls the function in the field.

value.method, without parentheses, is a function value that holds the value, and Type.method is one that takes the value as its first argument, so methods can be passed like other functions:

func() f64 measure = p.length
print(map([Point(1, 0), Point(0, 2)], Point.length))
func() Point make = Point.origin