<div><br><div class="gmail_quote"><div>On Fri, Jun 23, 2017 at 16:43 Robert Bennett via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hello Swift Evolution,<br>
<br>
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.<br>
<br>
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.<br>
<br>
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`.<br>
<br>
protocol P {<br>
    var x: Int { let }<br>
    init(_ x: Int)<br>
    func modifyX()<br>
}<br>
extension P {<br>
    init(_ x: Int) {<br>
        self.x = x // This is ok; would not be ok if x were marked { get }<br>
    }<br>
</blockquote><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"></blockquote><div><br></div><div>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 }`.</div><div><br></div><div>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&#39;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.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><br>
    func modifyX() {<br>
        self.x += 1 // Not allowed<br>
    }<br>
}<br>
<br>
struct S: P {<br>
    let x: Int // This is ok; would not be ok if x were marked { get set }<br>
}<br>
<br>
Option 2: `set(init)`. Can (and often will) coexist with `get`.<br>
<br>
protocol P {<br>
    var x: Int { get set(init) }<br>
    init(_ x: Int)<br>
    func modifyX()<br>
}<br>
extension P {<br>
    init(_ x: Int) {<br>
        self.x = x // This is ok; would not be ok if x were marked { get }<br>
    }<br>
<br>
    func modifyX() {<br>
        self.x += 1 // Not allowed<br>
    }<br>
}<br>
<br>
struct S: P {<br>
    let x: Int // This is ok; would not be ok if x were marked { get set }<br>
}<br>
<br>
<br>
I’d like to hear all of your thoughts on this.<br>
<br>
Best,<br>
Robert<br>
_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
</blockquote></div></div>