[swift-evolution] [Proposal] Uniform Initialization Syntax

Xiaodi Wu xiaodi.wu at gmail.com
Fri Jun 9 06:07:52 CDT 2017

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/e0dc3214/attachment.html>

More information about the swift-evolution mailing list