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.
> 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] > <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] https://lists.swift.org/mailman/listinfo/swift-evolution
