For a concrete type, a partial initializer is a function that: Can set `let` instance variables May not refer to `self` in an rvalue Must set the same subset of instance variables regardless of the code path taken
For a protocol, a partial initializer is simply a function that sets *any* subset of the instance variables. A protocol could provide a default implementation of one. In order for this `let` proposal to work, though, if a `let` variable is set in the protocol extension’s implementation of a (full) initializer, the protocol would need to provide at least one partial initializer that it does not provide an implementation for, so that a conforming type can fill in the gaps for all of the instance variables it defines that the protocol doesn’t require/know about. That way the compiler can have faith that a conforming type will be able to fully initialize itself with the default implementation of the required full initializer. > On Jun 25, 2017, at 3:57 PM, Xiaodi Wu <xiaodi...@gmail.com> wrote: > > So your proposed definition of a partial initializer is one that does not set > any protocol requirement? > On Sun, Jun 25, 2017 at 14:54 Robert Bennett <rltbenn...@icloud.com > <mailto:rltbenn...@icloud.com>> wrote: > The compiler would only raise an error when a conforming type violated the > requirement that the partial initializer not set x. The protocol itself would > never fail to compile. > > On Jun 25, 2017, at 3:33 PM, Xiaodi Wu <xiaodi...@gmail.com > <mailto:xiaodi...@gmail.com>> wrote: > >> On Sun, Jun 25, 2017 at 2:24 PM, Robert Bennett via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote: >> You’re right Xiaodi, I did not entirely think this through. However I think >> this could still work with another addition to the language: partial >> initializers. These would be treated as initializers are now (meaning, for >> instance, no reference to self until initialization is complete) except they >> would only need to initialize a subset of the instance variables before >> exiting. An initializer could then satisfy the requirement that all instance >> variables must be initialized by calling partial initializers. >> >> By incorporating partial initializers, it would be possible to guarantee >> that a `let` variable in a protocol is only set once. This is because an >> init implemented in a protocol extension could delegate to a partial >> initializers required by the protocol, and because they are only partial >> initializers, they need not set the instance variables already set in the >> initializer; it would be up to a conforming type to ensure this is the caee. >> A confirming type would define the partial initializer to set everything not >> already set in the protocol extension’s init, and it would be a compiler >> error to set a variable in the partial initializer that is already set in >> the extension’s init without overriding the extension’s init. >> >> How can the compiler raise this error when the implementation of the partial >> initializer does not even have to exist at compile time? >> >> Example code: >> >> protocol P { >> var x: Int { let } // or { get set(init) }, or whatever >> >> partialinit initializeRest() >> init() >> } >> >> extension P { >> init() { >> initializeRest() >> >> How can the compiler ensure that `initializeRest()` does not already set `x`? >> >> self.x = 1 >> } >> } >> >> struct S: P { >> let x: Int >> var y: String >> >> // It would be a compiler error to set x here without also redefining >> init() >> partialinit initializeRest() { >> self.y = “P has no knowledge of me” >> } >> >> // Can use default init provided by P >> } >> >> > On Jun 23, 2017, at 8:12 PM, Karl Wagner <razie...@gmail.com >> > <mailto:razie...@gmail.com>> wrote: >> > >> > What you want is some way to guarantee value semantics when writing >> > generic code. >> > >> > It’s a known hole, and admittedly quite a big one. I hope that there will >> > be time for core language improvements like this in Swift 5. Be sure to >> > raise the issue again once planning for that starts! >> > >> > - Karl >> > >> >> On 23. Jun 2017, at 23:43, Robert Bennett via swift-evolution >> >> <swift-evolution@swift.org <mailto:swift-evolution@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 } >> >> } >> >> >> >> 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@swift.org <mailto:swift-evolution@swift.org> >> >> https://lists.swift.org/mailman/listinfo/swift-evolution >> >> <https://lists.swift.org/mailman/listinfo/swift-evolution> >> > >> _______________________________________________ >> swift-evolution mailing list >> swift-evolution@swift.org <mailto:swift-evolution@swift.org> >> https://lists.swift.org/mailman/listinfo/swift-evolution >> <https://lists.swift.org/mailman/listinfo/swift-evolution> >>
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution