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 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 
(swift-evolution@swift.org) 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

On Jun 10, 2017, at 12:43 PM, Gor Gyolchanyan <g...@gyolchanyan.com> 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 <rileytes...@gmail.com> 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
 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 
<swift-evolution@swift.org> 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 
<swift-evolution@swift.org> wrote:

On Fri, Jun 9, 2017 at 5:32 PM, Gor Gyolchanyan <g...@gyolchanyan.com> wrote:
Forked swift-evolution, created a draft proposal:

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 <xiaodi...@gmail.com> 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 <g...@gyolchanyan.com> 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 <xiaodi...@gmail.com> wrote:

On Fri, Jun 9, 2017 at 07:33 Gor Gyolchanyan <g...@gyolchanyan.com> 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 <xiaodi...@gmail.com> wrote:


On Fri, Jun 9, 2017 at 07:12 Gor Gyolchanyan <g...@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...@gmail.com> wrote:


On Fri, Jun 9, 2017 at 06:56 Gor Gyolchanyan <g...@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...@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@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 <gpar...@apple.com> wrote:


On Jun 8, 2017, at 5:09 AM, Gor Gyolchanyan via swift-evolution 
<swift-evolution@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     gpar...@apple.com     Runtime Wrangler



_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution






_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution



_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to