Blog

[Swift] Property Requirements of Protocol

Published 2 min read

A protocol can require the properties it wants from a struct, class, or enum.
A struct, class, or enum can implement the properties a protocol requires as either stored / computed.

Because it has to be implementable as a computed property too, which can't be defined with the let keyword,
properties in a protocol must always be declared with the var keyword, not let.

protocol SomeProtocol { let mustBeSettable: Int { get set } ERROR! let doesNotNeedToBeSettable: Int { get } ERROR! }

A property required with the let keyword causes a compile error,
so apart from type properties, the requirement forms for properties in a protocol are roughly these two.

protocol SomeProtocol { var doesNotNeedToBeSettable: Int { get } var mustBeSettable: Int { get set } }

Properties declared like this can be implemented as either stored / computed properties.
Here, the let / var rules you have to follow for the two forms above are as follows.

① gettable

protocol SomeProtocol { var doesNotNeedToBeSettable: Int { get } } // Stored property struct varStoredProperty: SomeProtocol { var doesNotNeedToBeSettable: Int = 3 } struct letStoredProperty: SomeProtocol { let doesNotNeedToBeSettable: Int } // Computed property struct getComputedProperty: SomeProtocol { var doesNotNeedToBeSettable: Int { get { 3 } set {} } } struct getSetComputedProperty: SomeProtocol { var doesNotNeedToBeSettable: Int { get { 3 } } }

(no need to worry about the properties' default values)
A property required only as gettable can be implemented with every form of stored / computed property we can write.
The case where the implementation form gets constrained is a property required to be gettable and settable.

② gettable, settable

protocol SomeProtocol { var doesNotNeedToBeSettable: Int { get set } } // Stored property struct varStoredProperty: SomeProtocol { var doesNotNeedToBeSettable: Int = 3 } // ERROR!: Type 'letStoredProperty' does not conform to protocol 'SomeProtocol' struct letStoredProperty: SomeProtocol { let doesNotNeedToBeSettable: Int } // Computed property struct getComputedProperty: SomeProtocol { var doesNotNeedToBeSettable: Int { get { 3 } set {} } } // ERROR!: Type 'getSetComputedProperty' does not conform to protocol 'SomeProtocol' struct getSetComputedProperty: SomeProtocol { var doesNotNeedToBeSettable: Int { get { 3 } } }

It absolutely has to have set, that is, the property that you can put in any value you want.
But a stored property's let can't be set except at initialization, only get,
and a computed property without set can't be set either, so you get an error.

So you might wonder if you have to memorize all this,
but if you know that a protocol can't require a property as { set } without get,
and keep in mind that expanding is allowed but narrowing isn't, there doesn't seem to be a need to memorize it.

When conforming to a property required only as gettable, you can add the settable trait and expand it,
but implementing a property that also requires settable as only gettable is narrowing it, so it's not allowed.

Comments

Leaving a comment stores your nickname (or GitHub profile info). Privacy policy

GitHub