On Sun, Jun 11, 2017 at 3:49 PM, Riley Testut <[email protected]> wrote:
> Some thoughts on updated proposal: > > • I strongly believe factory initializers should follow the progressive > disclosure pattern, and importing all Objective-C initializers as factory > initializers breaks this. While there is precedent for this because of the > "open" access control, I'd prefer if maybe we compromised and any @objc > initializer is assumed to have the same performance characteristics as a > factory initializer, without having to prepend the factory keyword. > I'm not expert enough on Obj-C interop issues to make insightful comments on this, but my naive impression here is that changing how _all_ Obj-C initializers are imported by default seems...risky? Perhaps a summary of how the compiler currently handles the issue is in order for this proposal, so as to enable readers to evaluate this change. > • While I did initially propose the factory keyword, I'm still not > entirely sure "factory" is the right choice. Though if the consensus that > is the right keyword, then I'll happily accept that. > • Having "self" refer to the dynamic *type* of the returned instance > seems...weird. While technically correct for a static method, I'd expect > self to be an instance and Self to be the dynamic type just like any other > initializer. > Agree: `self` referring to a type is unprecedented when it's not a static method--this feels weird. If this is essential for the whole design, have you considered maybe just calling it `static init`? (This raises a potentially interesting thought about whether it'd make sense to also have a `class init`...) • Factory initializers should be used for *any *initializer that returns a > value. Furthermore, I don't think we should limit factory initializers to > just protocol extensions and classes. Sure it doesn't make sense for value > types, but I don't think we should forbid that (and that way if you want to > return a value instead of a assign to self, you'd just use factory > intializer) > • I don't think there should be *any* delegating to other factory > initializers. Nothing would stop you from returning a value initialized via > another factory method, however. > Hmm. That sounds workable and simpler, definitely. Sorry if sounds a little rambled, don't have access to a computer for the > rest of the day so typing this all up on my phone! > > On Jun 11, 2017, at 1:39 PM, Gor Gyolchanyan via swift-evolution < > [email protected]> wrote: > > Here's the updated proposal: > > https://github.com/technogen-gg/swift-evolution/blob/ > master/proposals/NNNN-factory-initializers.md > > Is there anything else or are we good to go? > > On Jun 11, 2017, at 8:46 PM, Xiaodi Wu <[email protected]> wrote: > > On Sun, Jun 11, 2017 at 12:43 PM, Gor Gyolchanyan <[email protected]> > wrote: > >> I have no better name besides a factory initializer for now. >> I have thought about this some more and came to this conclusion about the >> keyword: >> Let the keyword be universally applied to all factory initializers, to >> statically enforce the rules of factory initializers (see below), because >> the more I think of it, the more I realize that you'd generally not want to >> mix factory and non-factory initializers, due to their vastly differing >> purposes. >> >> Having said that, my current understanding of this proposal is as follows: >> >> * Allow marking initializers inside protocol extensions, class >> declarations and class extensions as `factory`. >> * In initializers marked as `factory`: >> * Change the implicit `self` parameter to mean `the dynamic type of the >> enclosing type` (just like it does in static methods). >> * Disallow delegating initialization to initializers not marked as >> `factory`. >> * Require terminating the initializer by either returning a compatible >> type (a conforming type for protocols, a derived instance for classes) or >> returning `nil` (if the initializer is failable). >> * In initializers inside enum declarations, enum extensions, struct >> declarations and struct extensions: >> * Allow terminating the initializer by returning an instance of the type >> being initialized. >> > > Sounds reasonable to me. > > On Jun 11, 2017, at 7:38 PM, Xiaodi Wu <[email protected]> wrote: >> >> On Sun, Jun 11, 2017 at 10:34 AM, Gor Gyolchanyan <[email protected]> >> wrote: >> >>> I just didn't want to use the commonly proposed `factory` word, because >>> it implies a specific semantic tied to the factory method pattern. >>> I gave it another thought and I'm thinking maybe we can forego the >>> annotation and have the compiler deduce it automatically. >>> There are only two places where an indirect initializer can exist: >>> * Protocol extensions, returning a conforming type. >>> * Classes, returning an instance. >>> It doesn't make sense to have this on value types, since they do not >>> have subtypes of any kind. >>> Indirect initializers are very unambiguous in protocol extensions, >>> because the only other way of implementing an initializer in a protocol >>> extension is via delegating initialization, so the indirect-ness of the >>> initializer can be statically determined by whether or not there is a >>> delegating initializer involved. >>> If the initializer in a protocol extension has a delegating >>> initialization on any execution path, then returning an instance is >>> disallowed and vice versa. This will ensure strict separation of >>> initializer types for the compiler to generate code for. >>> If a failable initializer in a protocol extension unconditionally >>> returns `nil`, then no initialization takes place anyway, so it doesn't >>> matter, which one the compiler chooses. >>> In classes this is a bit difficult, because besides delegating >>> initializers, they also can initialize the members directly. >>> So, in addition to the distinguishing rule for the protocol extensions, >>> classes will also check whether any member is assigned to on any execution >>> path. >>> >>> What do you think? >>> >> >> Keywords aren't just for the compiler; they're for the human reader too! >> If you believe the use of your proposed feature in protocol extensions is >> unambiguous to humans as well as compilers, then IMO it makes sense not to >> require another keyword in that place. I haven't thought deeply about >> whether that would be the case. >> >> Clearly, you're saying that this is a more complicated situation with >> classes; I think it makes sense for you to consider requiring a keyword >> there. There is precedent for keywords modifying `init` to be required for >> classes but not for value types (e.g., `convenience`). >> >> Regardless of whether a keyword is required or not, your feature needs a >> name. And here again, I think it is puzzling that you are calling them >> "indirect initializers" when there is already another meaning for >> "indirect" in Swift. Distinct concepts should have distinct names. >> >> On Jun 11, 2017, at 5:53 PM, Xiaodi Wu <[email protected]> wrote: >>> >>> On Sun, Jun 11, 2017 at 8:49 AM, Gor Gyolchanyan <[email protected]> >>> wrote: >>> >>>> Can you recall the reasons why the removal of access modifiers on >>>> extensions was rejected? >>>> >>> >>> It was an unassailable reason, really: people found this shorthand >>> useful and wanted to continue to use it--it is the only way to specify that >>> multiple members are public without explicitly labeling each one. The core >>> team agreed it was useful. >>> >>> My takeaway from the whole episode (I was greatly in favor of removing >>> this shorthand, as it's highly inconsistent with all other access modifier >>> rules) is that in general, since the bar for new syntax is so high, if a >>> shorthand made it into the language (and especially if it's kind of an >>> inconsistent shorthand) the general presumption must be that it is highly >>> desired. >>> >>> Also, do you think `indirect init` is confusing inside an `indirect >>>> enum`? >>>> >>> >>> I do. These are unrelated definitions of "indirect," and I'm puzzled why >>> you'd actively choose to run into issues with the same word meaning two >>> things when you could choose another word. >>> >>> On Jun 11, 2017, at 4:40 PM, Xiaodi Wu <[email protected]> wrote: >>>> >>>> Removal of access modifiers on extensions has been proposed, reviewed, >>>> and rejected, so that’s that. >>>> >>>> In general, Swift uses distinct keywords for distinct concepts, unlike >>>> Rust which likes to reuse keywords in clever ways; if you’re finding that >>>> things are getting confusing with one word meaning two things, that >>>> shouldn’t be an invitation to rip out existing syntax but is probably a >>>> good sign you shouldn’t be repurposing that keyword. >>>> >>>> >>>> On Sun, Jun 11, 2017 at 03:28 Adrian Zubarev via swift-evolution < >>>> [email protected]> wrote: >>>> >>>>> Yeah, well I messed up my proposal from last year about removing the >>>>> access modifier on extensions and wish now I wasn’t that confused back >>>>> than >>>>> and made it right. >>>>> >>>>> The indirect keyword is literally the same story. The docs only says >>>>> that this is only a shortcut. >>>>> >>>>> „To enable indirection for all the cases of an enumeration, mark the >>>>> entire enumeration with the indirect modifier—this is convenient when the >>>>> enumeration contains many cases that would each need to be marked with the >>>>> indirect modifier.“ >>>>> >>>>> If you really wish to reuse that keyword here we might need to remove >>>>> such shortcuts from the language (indirect enum, access modifier on >>>>> extensions, anything else?). >>>>> >>>>> >>>>> >>>>> -- >>>>> Adrian Zubarev >>>>> Sent with Airmail >>>>> >>>>> Am 11. Juni 2017 um 10:12:38, Gor Gyolchanyan ([email protected]) >>>>> schrieb: >>>>> >>>>> I always wondered, why is `indirect` allowed on the `enum` itself? >>>>> Wouldn't it make more sense to apply it to individual cases that >>>>> recursively refer to the `enum`? >>>>> This question also applies to access modifiers on extensions. So, what >>>>> is it supposed to do? Change the default access modifier from `internal` >>>>> to >>>>> whatever I specify? That's just confusing, reduces readability and the >>>>> syntactic gain is marginal at best. >>>>> If the `indirect` confusion becomes real, I'd suggest getting rid of >>>>> `indirect enum` and using `indirect case` instead. >>>>> >>>>> On Jun 11, 2017, at 11:05 AM, Adrian Zubarev via swift-evolution < >>>>> [email protected]> wrote: >>>>> >>>>> The proposal is looking good to me. :) It will also enable easy >>>>> support for custom views using XIBs in iOS development without unnecessary >>>>> view nesting. >>>>> >>>>> For instance the function from this example https://stackoverflow. >>>>> com/a/43123783/4572536 could be used directly inside an init: >>>>> >>>>> class MyView : UIView { >>>>> >>>>> indirect init() { >>>>> return MyView.instantiateFromXib() >>>>> // Or after SR-0068 >>>>> return Self.instantiateFromXib() >>>>> } >>>>> } >>>>> >>>>> There is still one little thing that bothers me, it might be a little >>>>> bit confusing to have two different meanings of indirect on enums. >>>>> >>>>> indirect enum ArithmeticExpression { >>>>> case number(Int) >>>>> case addition(ArithmeticExpression, ArithmeticExpression) >>>>> case multiplication(ArithmeticExpression, ArithmeticExpression) >>>>> >>>>> // This might makes no sense, but it would still be possible after >>>>> // this proposal. >>>>> indirect init(other: ArithmeticExpression) { >>>>> return other >>>>> } >>>>> >>>>> // Furthermore if the keyboard is applied to the enum >>>>> // directly all other `indirect` uses are inferred. >>>>> // Will this be implicitly `indirect` because of the previous fact? >>>>> init() { … } >>>>> } >>>>> >>>>> >>>>> >>>>> >>>>> -- >>>>> Adrian Zubarev >>>>> Sent with Airmail >>>>> >>>>> Am 11. Juni 2017 um 00:38:56, Riley Testut via swift-evolution ( >>>>> [email protected]) schrieb: >>>>> >>>>> Awesome! Updated my proposal to include what I believed to be the >>>>> relevant portions of your indirect initializer idea. Let me know if >>>>> there’s >>>>> anything I missed or should change :-) >>>>> >>>>> https://github.com/rileytestut/swift-evolution/blob/master/p >>>>> roposals/NNNN-factory-initializers.md >>>>> >>>>> On Jun 10, 2017, at 12:43 PM, Gor Gyolchanyan <[email protected]> >>>>> wrote: >>>>> >>>>> Hi, Riley! >>>>> >>>>> I think that's a great idea! We can merge the second part of my >>>>> proposal (the `indirect init`) into your one and refine and consolidate >>>>> the >>>>> prerequisite proposal (about returning from `init` and possibly in-place >>>>> member initializers) and bunch them up into a proposal cluster (the way >>>>> swift coders did). >>>>> Feel free to tear out any chunks from my proposal, while I think about >>>>> a more in-depth rationale about revamping initialization syntax. 🙂 >>>>> >>>>> On Jun 10, 2017, at 8:36 PM, Riley Testut <[email protected]> >>>>> wrote: >>>>> >>>>> Hi Gor 👋 >>>>> >>>>> I’m very much in fan of a unified initialization syntax. I submitted >>>>> my own proposal for factory initializers a while back, but since it wasn’t >>>>> a focus of Swift 3 or 4 I haven’t followed up on it recently. In the time >>>>> since last working on it, I came to my own conclusion that rather than >>>>> focusing on factory initialization, the overall initialization process >>>>> should be simplified, which I’m glad to see someone else has realized as >>>>> well :-) >>>>> >>>>> Here’s my proposal for reference: https://github.com/ >>>>> apple/swift-evolution/pull/247/commits/58b5a93b322aae998eb40 >>>>> 574dee15fe54323de2e Originally I used the “factory” keyword, but I >>>>> think your “indirect” keyword may be a better fit (since it has precedent >>>>> in the language and is not limited to “just” being about factory >>>>> initialization). To divide your proposal up into smaller pieces for >>>>> review, >>>>> maybe we could update my proposal to use your indirect keyword, and then >>>>> start a separate topic/proposal for the remaining aspects of your >>>>> proposal? >>>>> I agree that splitting it into smaller chunks may be better for the >>>>> process. >>>>> >>>>> Let me know what you think! >>>>> >>>>> Riley >>>>> >>>>> >>>>> On Jun 10, 2017, at 3:33 AM, Gor Gyolchanyan via swift-evolution < >>>>> [email protected]> wrote: >>>>> >>>>> >>>>> This is a very interesting read. >>>>> >>>>> Thanks you! I tried to make it as clear and detailed as possible. 🙂 >>>>> >>>>> >>>>> We did not discuss the 'indirect' idea at all on this list. Did you >>>>> come up with it just now? In any case, my suggestion as to moving forward >>>>> would be this: >>>>> >>>>> I was writing the proposal and was just about to write `factory init`, >>>>> when it occurred to me: enums already have a keyword that does something >>>>> very similar. It seemed to me that an initializer that doesn't initialize >>>>> the instance in-place, but returns a completely separate instance from >>>>> somewhere else, is kinda "indirectly" initializing the instance. Plus, the >>>>> already established keyword and its semantic would reduce the learning >>>>> curve for this new feature and separate it from a single specific use case >>>>> (the "factory method" pattern). >>>>> >>>>> >>>>> - Do you feel that both halves of your draft (expanding `return` in >>>>> initializers, and `indirect` initializers) should absolutely be one >>>>> proposal, or can they be separated? >>>>> >>>>> I think the `return` can be easily implemented first, while opening up >>>>> an opportunity to later implement `indirect init`. The reason why I >>>>> unified >>>>> them was that the `return` idea on its own has very limited merit and >>>>> could >>>>> the thought of as a low-priority cosmetic enhancement. I wouldn't want it >>>>> to be viewed that way because the primary purpose of that idea is to >>>>> enable >>>>> `indirect init` (which Cocoa and Cocoa Touch developers would be very >>>>> happy >>>>> about). >>>>> >>>>> >>>>> a) If they can be separated because each half has individual merit, >>>>> then these ideas may be more likely to succeed as separate proposals, as >>>>> each can be critiqued fully and judged independently as digestible units. >>>>> >>>>> >>>>> Very good point. The challenge is to correctly separate them, without >>>>> losing context in their respective proposals and without bleeding the >>>>> proposals into each other. >>>>> >>>>> >>>>> >>>>> b) If you intend to tackle all your ideas all at once, that's going to >>>>> be a much bigger change--in terms of review effort, likely bikeshedding, >>>>> and implementation effort. It'll probably be best to solicit initial >>>>> feedback on this list first about `indirect` initializers, even if just to >>>>> familiarize the community with the idea, before launching into a pitch of >>>>> the whole proposal. >>>>> >>>>> I'd never send a pull request to swift-evolution without thoroughly >>>>> discussing it here. I just though, if I'm going to write a whole proposal >>>>> with examples and motivation, it would be easier to demonstrate it and >>>>> discuss in with the community If I just went ahead and wrote the whole >>>>> thing and sent the link. This way it would be clearer to the reader and >>>>> the >>>>> discussed changes would be accurately reflected by the commits I'd make to >>>>> my proposal. >>>>> >>>>> Original Message >>>>> >>>>> On Jun 10, 2017, at 2:38 AM, Daryle Walker via swift-evolution < >>>>> [email protected]> wrote: >>>>> >>>>> On Fri, Jun 9, 2017 at 5:32 PM, Gor Gyolchanyan <[email protected]> >>>>> wrote: >>>>> >>>>>> Forked swift-evolution, created a draft proposal: >>>>>> >>>>>> https://github.com/technogen-gg/swift-evolution/blob/master/ >>>>>> proposals/NNNN-uniform-initialization.md >>>>>> >>>>>> This is my first proposal, so I might have missed something or >>>>>> composed it wrong, so please feel free to comment, fork and send pull >>>>>> requests. 🙂 >>>>>> >>>>>> >>>>> This is a very interesting read. We did not discuss the 'indirect' >>>>> idea at all on this list. Did you come up with it just now? In any case, >>>>> my >>>>> suggestion as to moving forward would be this: >>>>> >>>>> - Do you feel that both halves of your draft (expanding `return` in >>>>> initializers, and `indirect` initializers) should absolutely be one >>>>> proposal, or can they be separated? >>>>> >>>>> a) If they can be separated because each half has individual merit, >>>>> then these ideas may be more likely to succeed as separate proposals, as >>>>> each can be critiqued fully and judged independently as digestible units. >>>>> >>>>> b) If you intend to tackle all your ideas all at once, that's going to >>>>> be a much bigger change--in terms of review effort, likely bikeshedding, >>>>> and implementation effort. It'll probably be best to solicit initial >>>>> feedback on this list first about `indirect` initializers, even if just to >>>>> familiarize the community with the idea, before launching into a pitch of >>>>> the whole proposal. >>>>> >>>>> >>>>> On Jun 9, 2017, at 3:24 PM, Xiaodi Wu <[email protected]> wrote: >>>>>> >>>>>> Cool. I have reservations about idea #3, but we can tackle that >>>>>> another day. (Real life things beckon.) But suffice it to say that I now >>>>>> really, really like your idea #2. >>>>>> On Fri, Jun 9, 2017 at 08:06 Gor Gyolchanyan <[email protected]> >>>>>> wrote: >>>>>> >>>>>>> You know, come to think of it, I totally agree, and here's why: >>>>>>> A normal initializer (if #2 is accepted) would *conceptually* have >>>>>>> the signature: >>>>>>> >>>>>>> mutating func `init`(...) -> Self >>>>>>> >>>>>>> Which would mean that both `self` and the returned result are >>>>>>> non-optional. >>>>>>> A failable initializer could then have the signature: >>>>>>> >>>>>>> mutating func `init`() -> Self? >>>>>>> >>>>>>> Which would make the returned result optional, but leave `self` >>>>>>> non-optional. >>>>>>> This would make `return nil` less out-of-place, like you said, while >>>>>>> still leaving `self` as a set-exactly-once `inout Self`. >>>>>>> A factory initializer would then have the signature: >>>>>>> >>>>>>> static func `init`(...) -> Self >>>>>>> >>>>>>> or in case of a failable factory initializer: >>>>>>> >>>>>>> static func `init`(...) -> Self? >>>>>>> >>>>>>> Which would still make sense with the now legal `return ...` syntax, >>>>>>> while adding the restriction of not having any `self` at all. >>>>>>> So, annotating the initializer with the keyword `factory` would >>>>>>> cause it to change the signature as well as remove any compiler >>>>>>> assumptions >>>>>>> about the dynamic type of the returned instance. >>>>>>> >>>>>>> In addition, idea #3 would be available for more deterministic >>>>>>> in-place initialization. >>>>>>> >>>>>>> On Jun 9, 2017, at 2:47 PM, Xiaodi Wu <[email protected]> wrote: >>>>>>> >>>>>>> On Fri, Jun 9, 2017 at 07:33 Gor Gyolchanyan <[email protected]> >>>>>>> wrote: >>>>>>> >>>>>>>> So far, we've discussed two ways of interpreting `self = nil`, both >>>>>>>> of which have a sensible solution, in my opinion: >>>>>>>> >>>>>>>> 1. It's a special rule like you said, which can be seen as >>>>>>>> counter-intuitive, but recall that `return nil` is just as much of a >>>>>>>> special rule and is also largely counter-intuitive. >>>>>>>> >>>>>>> >>>>>>> `return nil` is “special,” but it doesn’t conflict with any other >>>>>>> syntax because the initializer notionally has no return value. >>>>>>> Personally, >>>>>>> I have always disliked `return nil` in failable initializers for that >>>>>>> reason, but I couldn’t come up with a better alternative. >>>>>>> >>>>>>> Your proposed idea to allow returning any value is interesting >>>>>>> because, in the case of a failable initializer, `return nil` continues >>>>>>> to >>>>>>> have the same meaning if we consider the return value of the >>>>>>> initializer to >>>>>>> be of type `Self?`. For that reason, I think your idea #2 is quite >>>>>>> clever, >>>>>>> and it would go a long way in making `return nil` a lot less odd. It >>>>>>> also >>>>>>> increases the expressivity of initializers because it allows one to set >>>>>>> the >>>>>>> value of self and also return in one statement, clearly demonstrating >>>>>>> the >>>>>>> intention that no other code in the initializer should be run before >>>>>>> returning. >>>>>>> >>>>>>> For all of those reasons, I think idea #2 is a winning idea. >>>>>>> >>>>>>> The benefit of `self = nil` is that it's much more in line with >>>>>>>> initialization semantics, it provides more uniform syntax and it's a >>>>>>>> bit >>>>>>>> less restrictive. >>>>>>>> >>>>>>>> 2. It's an `inout Self!`, like Greg said, which can be seen as more >>>>>>>> cumbersome. Implicitly unwrapped optionals are a bit difficult, but >>>>>>>> this >>>>>>>> "variation" of it is much more restrictive then the normal ones, >>>>>>>> because >>>>>>>> unlike normal implicitly unwrapped optionals, this one cannot be >>>>>>>> accessed >>>>>>>> after being assigned nil (and it also cannot be indirectly assigned >>>>>>>> `nil`, >>>>>>>> because escaping `self` is not allowed before full initialization), so >>>>>>>> there is only one possible place it can be set to nil and that's >>>>>>>> directly >>>>>>>> in the initializer. This means that `self` can be safely treated as >>>>>>>> `inout >>>>>>>> Self` before being set to nil (and after being set to nil, it doesn't >>>>>>>> matter any more because you aren't allowed to access it, due to not >>>>>>>> being >>>>>>>> fully initialized). >>>>>>>> >>>>>>> >>>>>>> I have to say, I don’t like either of these explanations at all. I >>>>>>> think having a “special” IUO is a difficult sell; it is just >>>>>>> conceptually >>>>>>> too complicated, and I don’t agree that it gains you much. >>>>>>> >>>>>>> By your own admission, `self = nil` is wonky, and making the >>>>>>> language wonkier because it currently has a parallel wonky feature in >>>>>>> `return nil` seems like the wrong way to go. In addition, there’s >>>>>>> nothing >>>>>>> gained here that cannot be done with a defer statement; of course, defer >>>>>>> statements might not be very elegant, but it would certainly be less >>>>>>> wonky >>>>>>> than inventing a new variation on an IUO to allow assignment of nil to >>>>>>> self... For those reasons, I conclude that I’m not excited about your >>>>>>> idea >>>>>>> #1. >>>>>>> >>>>>>> Overall, I'd go with #2 because it involves much less confusing >>>>>>>> magic and the restrictions of `self as inout Self!` are imposed by >>>>>>>> already >>>>>>>> existing and well-understood initialization logic, so the provided >>>>>>>> guarantees don't really come at the cost of much clarity. >>>>>>>> >>>>>>>> On Jun 9, 2017, at 2:23 PM, Xiaodi Wu <[email protected]> wrote: >>>>>>>> >>>>>>>> >>>>>>>> On Fri, Jun 9, 2017 at 07:12 Gor Gyolchanyan <[email protected]> >>>>>>>> wrote: >>>>>>>> >>>>>>>>> I think a good approach would be to have `self = nil` only mean >>>>>>>>> `the initializer is going to fail` because if your type is >>>>>>>>> ExpressibleByNilLiteral, it means that the `nil` of your type already >>>>>>>>> carries the same meaning as if your type was not >>>>>>>>> ExpressibleByNilLiteral >>>>>>>>> and was an optional instead, so having a failable initializer doesn't >>>>>>>>> really make sense in that case (since you could've initialized `self` >>>>>>>>> to >>>>>>>>> its own `nil` in case of failure). Still, some valid use cases may >>>>>>>>> exist, >>>>>>>>> so the natural (and quite intuitive) way to circumvent this would be >>>>>>>>> to >>>>>>>>> call `self.init(nilLiteral: ())` directly. >>>>>>>>> >>>>>>>> >>>>>>>> So you would create a special rule that `self = nil` means a >>>>>>>> different thing in an initializer than it does in a function? >>>>>>>> Essentially, >>>>>>>> then, you’re creating your own variation on an implicitly unwrapped >>>>>>>> optional, where `self` is of type `inout Self?` for assignment in >>>>>>>> initializers only but not for any other purpose. Implicitly unwrapped >>>>>>>> optionals are hard to reason about, and having a variation on it would >>>>>>>> be >>>>>>>> even harder to understand. I don’t think this is a workable design. >>>>>>>> >>>>>>>> It might be possible to have `self` be of type `inout Self?`; >>>>>>>> however, I do think Greg is right that it would create more boilerplate >>>>>>>> than the current situation. >>>>>>>> >>>>>>>> On Jun 9, 2017, at 2:07 PM, Xiaodi Wu <[email protected]> wrote: >>>>>>>>> >>>>>>>>> >>>>>>>>> On Fri, Jun 9, 2017 at 06:56 Gor Gyolchanyan <[email protected]> >>>>>>>>> wrote: >>>>>>>>> >>>>>>>>>> The type of `self` could remain `inout Self` inside the failable >>>>>>>>>> initializer. The ability to assign nil would be a compiler magic >>>>>>>>>> (much like >>>>>>>>>> `return nil` is compiler magic) that is meant to introduce >>>>>>>>>> uniformity to >>>>>>>>>> the initialization logic. >>>>>>>>>> >>>>>>>>>> The idea is to define all different ways initialization can take >>>>>>>>>> place and expand them to be used uniformly on both `self` and all its >>>>>>>>>> members, as well as remove the ways that do not make sense for their >>>>>>>>>> purpose. >>>>>>>>>> >>>>>>>>>> Currently, there are 3 ways of initializing self as a whole: >>>>>>>>>> 1. delegating initializer >>>>>>>>>> 2. assigning to self >>>>>>>>>> 3. returning nil >>>>>>>>>> >>>>>>>>>> #1: The delegating initializer is pretty much perfect at this >>>>>>>>>> point, in my opinion, so no changes there. >>>>>>>>>> >>>>>>>>>> #2: The only exception in assigning to self is the `nil` inside >>>>>>>>>> failable initializers. >>>>>>>>>> >>>>>>>>>> #3: The only thing that can be returned from an initializer is >>>>>>>>>> `nil`, which is compiler magic, so we can thing of it as a misnomer >>>>>>>>>> (because we aren't really **returning** anything). >>>>>>>>>> >>>>>>>>>> If, for a second, we forget about potential factory initializers, >>>>>>>>>> returning anything from an initializer doesn't make much sense, >>>>>>>>>> because an >>>>>>>>>> initializer is conceptually meant to bring an existing object in >>>>>>>>>> memory to >>>>>>>>>> a type-specific valid state. This semantic was very explicitly in >>>>>>>>>> Objective-C with `[[MyType alloc] init]`. Especially since even >>>>>>>>>> syntactically, the initializer does not specify any return type, the >>>>>>>>>> idea >>>>>>>>>> of returning from an initializer is counter-intuitive both >>>>>>>>>> syntactically >>>>>>>>>> and semantically. >>>>>>>>>> >>>>>>>>>> The actual *behavior* of `return nil` is very sensible, so the >>>>>>>>>> behavior, I imagine `self = nil`, would largely mean the same >>>>>>>>>> (except not >>>>>>>>>> needed to return immediately and allowing non-self-accessing code to >>>>>>>>>> be >>>>>>>>>> executed before return). Being able to assign `nil` to a non-optional >>>>>>>>>> (ExpressibleByNilLiteral doesn't count) may feel a bit wonky, >>>>>>>>>> >>>>>>>>> >>>>>>>>> What happens when Self is ExpressibleByNilLiteral and you want to >>>>>>>>> initialize self to nil? That is what `self = nil` means if `self` is >>>>>>>>> of >>>>>>>>> type `inout Self`. If `self` is of type `inout Self` and Self is not >>>>>>>>> ExpressibleByNilLiteral, then it must be an error to assign nil to >>>>>>>>> self. >>>>>>>>> Anything else does not make sense, unless `self` is of type `inout >>>>>>>>> Self?`. >>>>>>>>> >>>>>>>>> but not as wonky as returning nil from something that is meant to >>>>>>>>>> initialize an object in-place and doesn't look like it should return >>>>>>>>>> anything. >>>>>>>>>> >>>>>>>>>> # Factory Initializers >>>>>>>>>> >>>>>>>>>> In case of factory initializers, the much discussed `factory >>>>>>>>>> init` syntax could completely flip this logic, but making the >>>>>>>>>> initializer >>>>>>>>>> essentially a static function that returns an object. In this case >>>>>>>>>> the >>>>>>>>>> initializer could be made to specify the return type (that is the >>>>>>>>>> supertype >>>>>>>>>> of all possible factory-created objects) and assigning to self would >>>>>>>>>> be >>>>>>>>>> forbidden because there is not self yet: >>>>>>>>>> >>>>>>>>>> extension MyProtocol { >>>>>>>>>> >>>>>>>>>> public factory init(weCool: Bool) -> MyProtocol { >>>>>>>>>> self = MyImpl() // error: cannot assign to `self` in a factory >>>>>>>>>> initializer >>>>>>>>>> self.init(...) // error: cannot make a delegating initializer >>>>>>>>>> call in a factory initializer >>>>>>>>>> if weCool { >>>>>>>>>> return MyCoolImpl() >>>>>>>>>> } else { >>>>>>>>>> return MyUncoolImpl() >>>>>>>>>> } >>>>>>>>>> } >>>>>>>>>> >>>>>>>>>> } >>>>>>>>>> >>>>>>>>>> # In-place Member Initializers >>>>>>>>>> >>>>>>>>>> In addition, member initialization currently is only possible >>>>>>>>>> with #2 (as in `self.member = value`), which could be extended in a >>>>>>>>>> non-factory initializer to be initializable in-place like this: >>>>>>>>>> >>>>>>>>>> self.member.init(...) >>>>>>>>>> >>>>>>>>>> This would compliment the delegating initialization syntax, while >>>>>>>>>> giving a more reliable performance guarantee that this member will >>>>>>>>>> not be >>>>>>>>>> copy-initialized. >>>>>>>>>> >>>>>>>>>> On Jun 9, 2017, at 1:32 PM, Xiaodi Wu <[email protected]> >>>>>>>>>> wrote: >>>>>>>>>> >>>>>>>>>> If `self` is not of type `inout Self?`, then what is the type of >>>>>>>>>> `self` such that you may assign it a value of `nil`? >>>>>>>>>> >>>>>>>>>> It certainly cannot be of type `inout Self`, unless `Self` >>>>>>>>>> conforms to `ExpressibleByNilLiteral`, in which case you are able to >>>>>>>>>> assign >>>>>>>>>> `self = nil` an unlimited number of times–but that has a totally >>>>>>>>>> different >>>>>>>>>> meaning. >>>>>>>>>> >>>>>>>>>> Could `self` be of type `inout Self!`? Now that implicitly >>>>>>>>>> unwrapped optionals are no longer their own type, I’m not sure that’s >>>>>>>>>> possible. But even if it were, that seems unintuitive and potentially >>>>>>>>>> error-prone. >>>>>>>>>> >>>>>>>>>> So I think Greg is quite right that, to enable this feature, >>>>>>>>>> `self` would have to be of type `inout Self?`–which is intriguing but >>>>>>>>>> potentially more boilerplatey than the status quo. >>>>>>>>>> On Fri, Jun 9, 2017 at 05:24 Gor Gyolchanyan via swift-evolution < >>>>>>>>>> [email protected]> wrote: >>>>>>>>>> >>>>>>>>>>> Good point, but not necessarily. >>>>>>>>>>> Since you cannot access `self` before it being fully initialized >>>>>>>>>>> and since `self` can only be initialized once, this would mean that >>>>>>>>>>> after >>>>>>>>>>> `self = nil`, you won't be allowed to access `self` in your >>>>>>>>>>> initializer at >>>>>>>>>>> all.You'll be able to do any potential, cleanup though. >>>>>>>>>>> Also, since there can be only one `self = nil`, there's no >>>>>>>>>>> reason to treat `self` as `inout Self?`, because the only place it >>>>>>>>>>> can be >>>>>>>>>>> `nil` is the place it cannot be accessed any more. >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> On Jun 9, 2017, at 7:45 AM, Greg Parker <[email protected]> >>>>>>>>>>> wrote: >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> On Jun 8, 2017, at 5:09 AM, Gor Gyolchanyan via swift-evolution < >>>>>>>>>>> [email protected]> wrote: >>>>>>>>>>> >>>>>>>>>>> 1. Arbitrary `self` Assignments In Intializers >>>>>>>>>>> >>>>>>>>>>> The first ideas is to allow `self = nil` inside failable >>>>>>>>>>> initializers (essentially making `self` look like `inout Self?` >>>>>>>>>>> instead of >>>>>>>>>>> `inout Self` with magical `return nil`), so that all initializers >>>>>>>>>>> uniformly >>>>>>>>>>> can be written in `self = ...` form for clarity and convenience >>>>>>>>>>> purposes. >>>>>>>>>>> This should, theoretically, be nothing but a `defer { return nil }` >>>>>>>>>>> type of >>>>>>>>>>> rewrite, so I don't see any major difficulties implementing this. >>>>>>>>>>> This is >>>>>>>>>>> especially useful for failable-initializing enums where the main >>>>>>>>>>> switch >>>>>>>>>>> simply assigns to self in all cases and the rest of the initializer >>>>>>>>>>> does >>>>>>>>>>> some post-processing. >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> I don't see how to avoid source incompatibility and uglification >>>>>>>>>>> of failable initializer implementations here. Allowing `self = nil` >>>>>>>>>>> inside >>>>>>>>>>> a failable initializer would require `self` to be an optional. That >>>>>>>>>>> in turn >>>>>>>>>>> would require every use of `self` in the initializer to be >>>>>>>>>>> nil-checked or >>>>>>>>>>> forced. I don't think that loss everywhere outweighs the gain of >>>>>>>>>>> `self = >>>>>>>>>>> nil` in some places. >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> -- >>>>>>>>>>> Greg Parker [email protected] Runtime Wrangler >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> _______________________________________________ >>>>>>>>>>> swift-evolution mailing list >>>>>>>>>>> [email protected] >>>>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>>>>>>>>> >>>>>>>>>> >>>>>>>>> >>>>>>>> >>>>>>> >>>>>> >>>>> >>>>> _______________________________________________ >>>>> swift-evolution mailing list >>>>> [email protected] >>>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>>>> >>>>> >>>>> >>>>> >>>>> _______________________________________________ >>>>> swift-evolution mailing list >>>>> [email protected] >>>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>>>> >>>>> >>>>> _______________________________________________ >>>>> swift-evolution mailing list >>>>> [email protected] >>>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>>>> >>>>> >>>>> _______________________________________________ >>>>> swift-evolution mailing list >>>>> [email protected] >>>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>>> >>>> >> > > _______________________________________________ > swift-evolution mailing list > [email protected] > https://lists.swift.org/mailman/listinfo/swift-evolution > >
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
