Skip to content

Methods ​

Implementation status: instance methods / static methods / override / protocol default implementations / mutating Implemented; @objc / KVO / inout parameters Not implemented

A method is a function associated with a type. SYX has four kinds of method: instance methods, static methods, initializers (init, see Chapter 15), and deinitializers (deinit, see Chapter 16). This chapter covers the first two plus overriding.

Instance Methods ​

swift
class Counter {
    var value: Int = 0
    func bump() { self.value = self.value + 1 }
    func increment(by n: Int) { self.value = self.value + n }
    func describe() -> String { return "Counter(\(self.value))" }
}

let c = Counter()
c.bump()
c.increment(by: 5)
print(c.describe())                        // "Counter(6)"
  • The implicit self may be omitted (when unambiguous); ambiguous cases need an explicit self.x
  • Named parameters work as in functions: label: value is required

Static Methods (static func) ​

swift
class Factory {
    static func create() -> Factory { return Factory() }
    static var defaultName: String = "anon"
}

let f = Factory.create()
print(Factory.defaultName)
CallForm
Type.method()static func / static var
instance.method()Instance method

static limits: static func has no self referring to an instance; it can access only other static members.

Protocol Default Implementations ​

A protocol may provide a default method implementation, and adopting types inherit the default:

swift
protocol Greetable {
    func greet() -> String
    func greet() -> String { return "Hello" }   // Default implementation
}

class User: Greetable {
    // Not implementing greet() inherits the protocol default → "Hello"
}

class Loud: Greetable {
    func greet() -> String { return "HI!" }    // Overrides the default
}

print(User().greet())                        // "Hello"
print(Loud().greet())                        // "HI!"

Overriding ​

A subclass overrides a superclass method (see Chapter 14, Inheritance):

swift
class Animal {
    func speak() { print("...") }
    func describe() -> String { return "Animal" }
}

class Dog: Animal {
    override func speak() { print("woof") }
    override func describe() -> String { return "Dog" }
}
  • The override keyword is mandatory
  • A missing override → S051
  • A method not declared in the superclass → S052

mutating Methods (struct / enum) ​

mutating func marks methods that modify self:

swift
struct Counter {
    var value: Int = 0
    mutating func increment() { value = value + 1 }
}

var c = Counter()
c.increment()
print(c.value)                             // 1

let c2 = Counter()
// c2.increment()                          // ❌ S020: cannot mutate immutable
  • It must be called on a var binding
  • A method body that modifies self without the mutating marker → compile error

Methods as Values ​

swift
class Helper {
    func shout(_ s: String) { print("!!! \(s) !!!") }
}

let h = Helper()
h.shout("hello")                             // !!! hello !!!
h.shout("world")                             // !!! world !!!
  • When binding a method you write no (); its type is the function type (P) -> R
  • f holds a strong reference to h (watch out for reference cycles)

Extension Methods ​

extension adds methods to an existing type (see Chapter 22, Extensions):

swift
extension Int {
    func doubled() -> Int { return self + self }
}

print(3.doubled())                           // 6

Subscript Methods ​

subscript declares a subscript inside a type (see Chapter 13, Subscripts):

swift
class Matrix {
    var data: Array<Array<Int>> = [[1, 2], [3, 4]]
    subscript(row: Int, col: Int) -> Int {
        get { return self.data[row][col] }
        set { self.data[row][col] = newValue }
    }
}

let m = Matrix()
print(m[0, 1])                               // 2

Static Storage ​

static var is type-level storage (shared across instances of a class):

swift
class Counter {
    static var totalInstances: Int = 0
    init() { Counter.totalInstances = Counter.totalInstances + 1 }
}

Counter()
Counter()
print(Counter.totalInstances)                // 2

Status: static var is Implemented (Phase 134+); willSet/didSet on a static var is Phase 138 GA (class only; see Chapter 11).

Methods and Actor Isolation ​

actor methods are isolated automatically:

swift
actor Counter {
    var value: Int = 0
    func increment() { self.value = self.value + 1 }   // Inside the isolation domain, value may be modified
}

let c = Counter()
await c.increment()                          // Crossing isolation requires await

Complete Example ​

swift
@Equatable
data class Point(x: Int, y: Int)

class Robot {
    var position: Point
    let id: Int
    static var nextId: Int = 0

    init(at p: Point) {
        self.position = p
        self.id = Robot.nextId
        Robot.nextId = Robot.nextId + 1
    }

    func moveTo(_ p: Point) {
        self.position = p
    }

    func describe() -> String {
        return "Robot #\(self.id) @ \(self.position)"
    }
}

func main() {
    let r1 = Robot(at: Point(x: 0, y: 0))
    let r2 = Robot(at: Point(x: 3, y: 4))
    r1.moveTo(Point(x: 1, y: 1))
    print(r1.describe())                      // "Robot #0 @ Point(x: 1, y: 1)"
    print(r2.position == Point(x: 3, y: 4))   // true
}

Diagnostics ​

CodeTriggerFix
S001Method name conflicts with a fieldRename it
S004Parameter / return type mismatchFix it
S020mutating called on a letChange it to var
S051Missing override keywordAdd override
S052Overriding something not declared in the superclassRemove override
A002Cross-actor call without awaitAdd await

Differences from Swift ​

SwiftSYX
@objc / @nonobjcNot implemented
inout parametersNot implemented; borrow with &mut T
final func forbidding overrideNot implemented (use final class)
mutating funcImplemented
@MainActor funcImplemented (see Chapter 18)
throws methodsImplemented (throws func fully supported)
async methodsImplemented (async func)

Next chapter → Subscripts

See also → Language Reference: Declarations · Chapter 11, Properties · Chapter 14, Inheritance · Chapter 22, Extensions

SYX · Apache-2.0