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

Reply via email to