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.
> 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]
> <mailto:[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]
>> <mailto:[email protected]>> wrote:
>>
>> On Sun, Jun 11, 2017 at 8:49 AM, Gor Gyolchanyan <[email protected]
>> <mailto:[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]
>>> <mailto:[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] <mailto:[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]
>>> <mailto:[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] <mailto:[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
>>>>> <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] <mailto:[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/proposals/NNNN-factory-initializers.md
>>>>>>
>>>>>> <https://github.com/rileytestut/swift-evolution/blob/master/proposals/NNNN-factory-initializers.md>
>>>>>>> On Jun 10, 2017, at 12:43 PM, Gor Gyolchanyan <[email protected]
>>>>>>> <mailto:[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]
>>>>>>>> <mailto:[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/58b5a93b322aae998eb40574dee15fe54323de2e
>>>>>>>>
>>>>>>>> <https://github.com/apple/swift-evolution/pull/247/commits/58b5a93b322aae998eb40574dee15fe54323de2e>
>>>>>>>> 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] <mailto:[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] <mailto:[email protected]>> wrote:
>>>>>>>>>>
>>>>>>>>>> On Fri, Jun 9, 2017 at 5:32 PM, Gor Gyolchanyan
>>>>>>>>>> <[email protected] <mailto:[email protected]>> wrote:
>>>>>>>>>> Forked swift-evolution, created a draft proposal:
>>>>>>>>>>
>>>>>>>>>> https://github.com/technogen-gg/swift-evolution/blob/master/proposals/NNNN-uniform-initialization.md
>>>>>>>>>>
>>>>>>>>>> <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]
>>>>>>>>>>> <mailto:[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]
>>>>>>>>>>> <mailto:[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]
>>>>>>>>>>>> <mailto:[email protected]>> wrote:
>>>>>>>>>>>>
>>>>>>>>>>>> On Fri, Jun 9, 2017 at 07:33 Gor Gyolchanyan <[email protected]
>>>>>>>>>>>> <mailto:[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]
>>>>>>>>>>>>> <mailto:[email protected]>> wrote:
>>>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>> On Fri, Jun 9, 2017 at 07:12 Gor Gyolchanyan
>>>>>>>>>>>>> <[email protected] <mailto:[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]
>>>>>>>>>>>>>> <mailto:[email protected]>> wrote:
>>>>>>>>>>>>>>
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> On Fri, Jun 9, 2017 at 06:56 Gor Gyolchanyan
>>>>>>>>>>>>>> <[email protected] <mailto:[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]
>>>>>>>>>>>>>>> <mailto:[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]
>>>>>>>>>>>>>>> <mailto:[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]
>>>>>>>>>>>>>>>> <mailto:[email protected]>> wrote:
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>> On Jun 8, 2017, at 5:09 AM, Gor Gyolchanyan via
>>>>>>>>>>>>>>>>> swift-evolution <[email protected]
>>>>>>>>>>>>>>>>> <mailto:[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] <mailto:[email protected]>
>>>>>>>>>>>>>>>> Runtime Wrangler
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>>
>>>>>>>>>>>>>>> _______________________________________________
>>>>>>>>>>>>>>> swift-evolution mailing list
>>>>>>>>>>>>>>> [email protected] <mailto:[email protected]>
>>>>>>>>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>>>>>>>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>> _______________________________________________
>>>>>>>>> swift-evolution mailing list
>>>>>>>>> [email protected] <mailto:[email protected]>
>>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> swift-evolution mailing list
>>>>>> [email protected] <mailto:[email protected]>
>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> swift-evolution mailing list
>>>>> [email protected] <mailto:[email protected]>
>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>>
>>> _______________________________________________
>>> swift-evolution mailing list
>>> [email protected] <mailto:[email protected]>
>>> https://lists.swift.org/mailman/listinfo/swift-evolution
>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution