[swift-evolution] [Pitch] `let` in protocols

Xiaodi Wu xiaodi.wu at gmail.com
Fri Jun 23 17:40:09 CDT 2017


On Fri, Jun 23, 2017 at 16:43 Robert Bennett via swift-evolution <
swift-evolution at swift.org> wrote:

> Hello Swift Evolution,
>
> I’m bumping into an annoying problem with protocols. In a class or struct
> it is common to have a `let` instance variable and assign it in `init`.
> Unfortunately there is no way to translate this into a protocol with init
> in an extension. If attempting to set the variable in init in an extension,
> it must be of type { get set }, which means it cannot be a `let` constant
> in the conforming type. AFAIK there is no way around this — if you want to
> set an instance variable in an initializer in a protocol extension, it must
> be marked as { get set }. The alternative is to write the initializer
> separately for each adopting type, but this violates DRY.
>
> Hence, I am proposing a third option to go along with `get` and `set` in a
> protocol. This would indicate that the variable can be a constant, but is
> settable in an initializer. In this case, the conforming type *must* use
> `let` to declare the variable.
>
> Option 1: the keyword `let`. If present, it would need to be the only
> thing in the curly brackets because it simultaneously implies `get` and not
> `set`.
>
> protocol P {
>     var x: Int { let }
>     init(_ x: Int)
>     func modifyX()
> }
> extension P {
>     init(_ x: Int) {
>         self.x = x // This is ok; would not be ok if x were marked { get }
>     }
>

The example given here requires an initializer on every conforming type for
reasons other than the requirement `x`, and your idea could not make it not
require such initializers. This is because, even though `P` only has one
required property `x`, types that conform to `P` can have any number of
properties. Therefore, you must chain the protocol extension initializer to
another one in order to guarantee initialization of all stored properties.
You can demonstrate this to yourself if you try to write this example in
Swift with `var x: Int { get set }`.

Moreover, even if you chained your initializer to another one *and* if it
were possible to express a requirement for a gettable property that is
settable exactly once, the example given here still would not work. This is
because the conforming type can have another initializer that is chained to
the required initializer--keep in mind that if the default implementation
of the required initializer is vended by a library, it may or may not set
the required property, and it may do so in one version but not another of
the library, so neither the author nor the compiler can reason about it.
Or, since the required initializer's default implementation must be chained
to another initializer, that initializer may or may not attempt to set the
property, and again there is no way to reason about whether or not this
will happen because the requirement, concrete type, and default
implementation can each live in a distinct module. Therefore, `self.x = x`
could not be permitted, even if a syntax were created to express a
requirement that `x` must be gettable and must be settable exactly once.


>     func modifyX() {
>         self.x += 1 // Not allowed
>     }
> }
>
> struct S: P {
>     let x: Int // This is ok; would not be ok if x were marked { get set }
> }
>
> Option 2: `set(init)`. Can (and often will) coexist with `get`.
>
> protocol P {
>     var x: Int { get set(init) }
>     init(_ x: Int)
>     func modifyX()
> }
> extension P {
>     init(_ x: Int) {
>         self.x = x // This is ok; would not be ok if x were marked { get }
>     }
>
>     func modifyX() {
>         self.x += 1 // Not allowed
>     }
> }
>
> struct S: P {
>     let x: Int // This is ok; would not be ok if x were marked { get set }
> }
>
>
> I’d like to hear all of your thoughts on this.
>
> Best,
> Robert
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170623/426fa5a3/attachment.html>


More information about the swift-evolution mailing list