Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift mutable set in property

Tags:

swift

protocol Deck {
var cards: [String] {get set} // {get mutable set}
}

struct MyDeck: Deck {   
 var cards: [String] =  (1...7).map {_ in return String(rand())}
}

Just interested do I need to specify {get mutable set} in protocol? Can't find any docs about why not using mutable keyword in setter declaration if my setter mutates my struct

like image 795
Shadowfax Avatar asked Dec 07 '22 22:12

Shadowfax


1 Answers

First of all note that the keyword of discussion is mutating, not mutable.


Default state of set is mutating

  • To swiftly answer your question: mutating is the default state for setters, and hence you needn't explicitly use the mutating keyword to specify this.

Details

For getter and setters, the following default behaviour holds

  • get is nonmutating as per default
  • set is mutating as per default

Hence, a protocol specifying ... { get set } for, say (as in your example), a computed property, expects the default nonmutating get and mutating set of a struct conforming to such a protocol

protocol Deck {
    var cards: [String] {get set}
}

// implicitly, OK
struct MyDeckA: Deck {
    var mutateMe: Int = 0
    var cards: [String] {
        get { return ["foo"] }
        set { mutateMe += 1 }
    }
}

// explicitly, OK
struct MyDeckB: Deck {
    var mutateMe: Int = 0
    var cards: [String] {
        nonmutating get { return ["foo"] }
        mutating set { mutateMe += 1 }
    }
}

/* error, MyDeckC does not conform to Deck 
  (mutating getter, wheres a nonmutating one is blueprinted!) */
struct MyDeckC: Deck {
    var mutateMe: Int = 0
    var cards: [String] {
        mutating get { return ["foo"] }
        mutating set { mutateMe += 1 }
    }
}

In case we want a getter or setter that deviates from the default cases above, we need to specify this (in the protocol as well as explicitly in say a struct conforming to such a protocol).

protocol Deck {
    var cards: [String] {mutating get nonmutating set}
}

/* when conforming to this non-default get/set setup blueprinted in 
   protocol Deck, we need to explicitly specify our non-default 
   (w.r.t. mutating) getter and setter */
struct MyDeckD: Deck {
    var mutateMe: Int = 0
    var cards: [String] {
        mutating get { mutateMe += 1; return ["foo"] }
        nonmutating set { print("I can't mutate self ...") }
    }
}

Finally, interestingly, if we (for some protocol property) blueprint a setter as the default (... {get set}), i.e., defaulted as mutating set, we may still conform to such a protocol with an explicitly nonmutating setter

protocol Deck {
    var cards: [String] {get set}
}

struct MyDeckE: Deck {
    var mutateMe: Int = 0
    var cards: [String] {
        get { return ["foo"] }
        nonmutating set { print("I can't mutate self ...") }
            /* setter cannot mutate self */
    }
}

I can assume that this is allowed as we let the structure that conforms to the protocol contain a setter that is more restrictive than the blueprinted one, with regard to mutating self. Naturally the same holds if we blueprint a mutating getter: we may still conform to such a protocol with a nonmutating one.

protocol Deck {
    var cards: [String] {mutating get set}
}

struct MyDeckF: Deck {
    var mutateMe: Int = 0
    var cards: [String] {
        nonmutating get { print("I can't mutate self ..."); return ["foo"] }
            /* getter cannot mutate self */
        set { mutateMe += 1 }
    }
}
like image 110
dfrib Avatar answered Apr 20 '23 21:04

dfrib