mut Function

A struct is a value type whose instance member functions cannot modify the instance. In the following example, the value of the member variable i cannot be changed by the member function g:

struct Foo {
    var i = 0

    public func g() {
        i += 1  // Error, the value of an instance member variable cannot be modified in an instance member function
    }
}

The mut function is a special instance member function that can modify the struct instance. In the mut function, this contains special semantics that allows it to modify fields in place.

Note:

The mut function can be defined only in an interface, struct, and struct extension. (A class is a reference type. Instance member functions can modify instance member variables without adding mut. Therefore, the mut function cannot be defined in a class.)

Definition

Compared with common instance member functions, the mut function has an additional modifier mut.

In the following example, the mut modifier is added before the g function, which allows the value of the member variable i to be changed in the function body:

struct Foo {
    var i = 0

    public mut func g() {
        i += 1  // Ok
    }
}

mut can be used to modify instance member functions only.

struct A {
    public mut func f(): Unit {} // Ok
    public mut operator func +(rhs: A): A { // Ok
        A()
    }
    public mut static func g(): Unit {} // Error, static member functions cannot be modified with 'mut'
}

this in the mut function cannot be captured or used as an expression. The instance member variables of a struct cannot be captured in the mut function.

Example:

struct Foo {
    var i = 0

    public mut func f(): Foo {
        let f1 = { => this } // Error, 'this' in mut functions cannot be captured
        let f2 = { => this.i = 2 } // Error, instance member variables in mut functions cannot be captured
        let f3 = { => this.i } // Error, instance member variables in mut functions cannot be captured
        let f4 = { => i } // Error, instance member variables in mut functions cannot be captured
        this // Error, 'this' in mut functions cannot be used as expressions
    }
}

mut Function in Interfaces

Instance member functions in interfaces can also be modified by mut.

The struct type must be modified by the same mut modifier when implementing an interface function. When a type other than struct implements an interface function, the mut modifier cannot be used.

Example:

interface I {
    mut func f1(): Unit
    func f2(): Unit
}

struct A <: I {
    public mut func f1(): Unit {} // Ok: as in the interface, the 'mut' modifier is used
    public func f2(): Unit {} // Ok: as in the interface, the 'mut' modifier is not used
}

struct B <: I {
    public func f1(): Unit {} // Error, 'f1' is modified with 'mut' in interface, but not in struct
    public mut func f2(): Unit {} // Error, 'f2' is not modified with 'mut' in interface, but did in struct
}

class C <: I {
    public func f1(): Unit {} // Ok
    public func f2(): Unit {} // Ok
}

When a struct instance is assigned to an interface type, the copy semantics is used. Therefore, the mut function of the interface cannot change the value of the struct instance.

Example:

interface I {
    mut func f(): Unit
}
struct Foo <: I {
    public var v = 0
    public mut func f(): Unit {
        v += 1
    }
}
main() {
    var a = Foo()
    var b: I = a  
    b.f()  // Calling 'f' via 'b' cannot modify the value of 'a'
    println(a.v) // 0
}

The program output is as follows:

0

Constraints on the mut Function

Since a struct is a value type, if a variable of the struct type is declared using let, the mut function of this type cannot be accessed through this variable.

Example:

interface I {
    mut func f(): Unit
}
struct Foo <: I {
    public var i = 0
    public mut func f(): Unit {
        i += 1
    }
}
main() {
    let a = Foo()
    a.f() // Error, 'a' is of type struct and is declared with 'let', the 'mut' function cannot be accessed via 'a'
    var b = Foo()
    b.f() // Ok
    let c: I = Foo()
    c.f() // Ok
}

To avoid escape, if the type of a variable is struct, the variable cannot use functions modified by mut as the first-class citizens, but it can still call these mut functions.

Example:

interface I {
    mut func f(): Unit
}

struct Foo <: I {
    var i = 0

    public mut func f(): Unit {
        i += 1
    }
}

main() {
    var a = Foo()
    var fn = a.f // Error, mut function 'f' of 'a' cannot be used as a first class citizen.
    var b: I = Foo()
    fn = b.f // Ok
}

To avoid escape, non-mut instance member functions (including lambda expressions) cannot directly access mut functions of the corresponding type, while the reverse is allowed.

Example:

struct Foo {
    var i = 0

    public mut func f(): Unit {
        i += 1
        g() // Ok
    }

    public func g(): Unit {
        f() // Error, mut functions cannot be invoked in non-mut functions
    }
}

interface I {
    mut func f(): Unit {
        g() // Ok
    }

    func g(): Unit {
        f() // Error, mut functions cannot be invoked in non-mut functions
    }
}