[swift-evolution] [Proposal] Uniform Initialization Syntax

Xiaodi Wu xiaodi.wu at gmail.com
Sun Jun 11 12:46:50 CDT 2017


On Sun, Jun 11, 2017 at 12:43 PM, Gor Gyolchanyan <gor at gyolchanyan.com>
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 <xiaodi.wu at gmail.com> wrote:
>
> On Sun, Jun 11, 2017 at 10:34 AM, Gor Gyolchanyan <gor at gyolchanyan.com>
> 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 <xiaodi.wu at gmail.com> wrote:
>>
>> On Sun, Jun 11, 2017 at 8:49 AM, Gor Gyolchanyan <gor at gyolchanyan.com>
>> 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 <xiaodi.wu at gmail.com> 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 <
>>> swift-evolution at swift.org> 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 (gor at gyolchanyan.com)
>>>> 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 <
>>>> swift-evolution at swift.org> 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 (
>>>> swift-evolution at swift.org) 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 <gor at gyolchanyan.com>
>>>> 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 <rileytestut at gmail.com>
>>>> 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 <
>>>> swift-evolution at swift.org> 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 <
>>>> swift-evolution at swift.org> wrote:
>>>>
>>>> On Fri, Jun 9, 2017 at 5:32 PM, Gor Gyolchanyan <gor at gyolchanyan.com>
>>>> 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 <xiaodi.wu at gmail.com> 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 <gor at gyolchanyan.com>
>>>>> 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 <xiaodi.wu at gmail.com> wrote:
>>>>>>
>>>>>> On Fri, Jun 9, 2017 at 07:33 Gor Gyolchanyan <gor at gyolchanyan.com>
>>>>>> 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 <xiaodi.wu at gmail.com> wrote:
>>>>>>>
>>>>>>>
>>>>>>> On Fri, Jun 9, 2017 at 07:12 Gor Gyolchanyan <gor at gyolchanyan.com>
>>>>>>> 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 <xiaodi.wu at gmail.com> wrote:
>>>>>>>>
>>>>>>>>
>>>>>>>> On Fri, Jun 9, 2017 at 06:56 Gor Gyolchanyan <gor at gyolchanyan.com>
>>>>>>>> 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 <xiaodi.wu at gmail.com> 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 <
>>>>>>>>> swift-evolution at swift.org> 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 <gparker at apple.com>
>>>>>>>>>> wrote:
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> On Jun 8, 2017, at 5:09 AM, Gor Gyolchanyan via swift-evolution <
>>>>>>>>>> swift-evolution at swift.org> 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     gparker at apple.com     Runtime Wrangler
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> _______________________________________________
>>>>>>>>>> swift-evolution mailing list
>>>>>>>>>> swift-evolution at swift.org
>>>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>
>>>>
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>
>>>>
>>>>
>>>>
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>
>>>>
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>
>>>>
>>>> _______________________________________________
>>>> 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/20170611/46ea6636/attachment.html>


More information about the swift-evolution mailing list