[swift-evolution] [Proposal] Uniform Initialization Syntax

Xiaodi Wu xiaodi.wu at gmail.com
Fri Jun 9 06:23:13 CDT 2017


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
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170609/16661117/attachment.html>


More information about the swift-evolution mailing list