<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">So instead of chaining convenience initializers to required ones via self.init(), you’d recommend instead assigning them directly to self? I think this would be a nice change; currently it can be hard to know the correct method of chaining initializers (at least as far as I’ve seen when attempting to explain it to newcomers).</div><div class=""><br class=""></div><div class="">Proposed new rules for initialization:</div><div class=""><br class=""></div><div class="">required initializers: must call super (unless base class)</div><div class="">convenience initializers: must assign to self via a required initializer</div><div class=""><br class=""></div><div class="">I think this also would help with the confusion of why convenience methods can’t call super, but required ones can, since now convenience methods can’t chain to <i class="">any</i> initializers directly. Thoughts from others?</div><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div class="">On Dec 7, 2015, at 1:17 PM, ilya <<a href="mailto:ilya.nikokoshev@gmail.com" class="">ilya.nikokoshev@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">more precisely like this for regular convenience initializers<div class=""><br class=""></div><div class="">class SomeClass {</div><div class=""><br class=""></div><div class=""> convenience init(x: Int) {</div><div class=""> let y = someComputation(x) // <- can't use self here</div><div class=""> self = init(y: y) </div><div class=""> self.configure() // <- can use self here</div><div class=""> }</div><div class=""> </div><div class=""> init(y:Int) { // designated</div><div class=""> ...</div><div class=""> }</div><div class="">}</div></div><div class="gmail_extra"><br class=""><div class="gmail_quote">On Tue, Dec 8, 2015 at 12:14 AM, ilya <span dir="ltr" class=""><<a href="mailto:ilya.nikokoshev@gmail.com" target="_blank" class="">ilya.nikokoshev@gmail.com</a>></span> wrote:<br class=""><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div dir="ltr" class="">Actually I think self = SomeClass(anotherInit: ...) would be a better syntax of choice for *all* convenience initializers, as it would make intuitively clear that self cannot be used until this call.</div><div class="HOEnZb"><div class="h5"><div class="gmail_extra"><br class=""><div class="gmail_quote">On Tue, Dec 8, 2015 at 12:11 AM, Riley Testut <span dir="ltr" class=""><<a href="mailto:rileytestut@gmail.com" target="_blank" class="">rileytestut@gmail.com</a>></span> wrote:<br class=""><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div dir="auto" class=""><div class=""></div><div class="">I actually really like the idea of using a convenience initializer for this, it works well with the Swift initiation process. +1 (though maybe a different keyword than "convenience" to show that it actually assigns to self?)</div><div class=""><div class=""><div class=""><br class="">On Dec 7, 2015, at 1:07 PM, ilya <<a href="mailto:ilya.nikokoshev@gmail.com" target="_blank" class="">ilya.nikokoshev@gmail.com</a>> wrote:<br class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div dir="ltr" class="">I actually like the way it's done in the Objective-C, where _isa pointer will be changed appropriately.<div class=""><br class=""></div><div class="">Perhaps it's actually possible to solve this problem:</div><div class=""><br class=""></div><div class="">> Unfortunately, this is wasteful; memory is allocated for the base class, and then subsequently replaced with new memory allocated for the appropriate base class. More importantly though, the whole process can be complicated;<br class=""></div><div class=""><br class=""></div><div class="">by noting that we can formally mark this initializer as convenience initializer, and memory allocation doesn't need to happen until we hit a designated initializer. So far I see no reason why this cannot be made to work:</div><div class=""><br class=""></div><div class="">class Cluster {</div><div class=""><br class=""></div><div class=""> convenience init(parameters) {</div><div class=""> if stuff {</div><div class=""> self = _Cluster1(...)</div><div class=""> } else {</div><div class=""> self = _Cluster2(...)</div><div class=""> }</div><div class=""><br class=""></div><div class=""> // it's safe to continue with second init phase</div><div class=""> self.configure(...)</div><div class=""> }</div><div class="">}</div><div class=""><br class=""></div><div class="">class _Cluster1 { </div><div class=""> init(parameters: ...) { ... } // designated init, guaranteed never to call convenience inits</div><div class="">}</div><div class=""><br class=""></div></div><div class="gmail_extra"><br class=""><div class="gmail_quote">On Mon, Dec 7, 2015 at 11:55 PM, David Owens II via swift-evolution <span dir="ltr" class=""><<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>></span> wrote:<br class=""><blockquote class="gmail_quote" style="margin: 0px 0px 0px 0.8ex; border-left-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; padding-left: 1ex;"><div class="" style="word-wrap: break-word;"><div class="">Well, the basic idea of a class cluster is to hide the internal implementation. The caller of the API is still supposed to get back an instance of the clustered type (or that conforms to the interface at least).</div><div class=""><br class=""></div><div class="">It’s still possible to create class clusters though; here’s an example playground:</div><div class=""><br class=""></div><blockquote class="" style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"><div class=""><font face="Menlo" class="">private protocol _Cluster {<br class=""> func description() -> String<br class="">}</font></div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class="">class Cluster {</font></div><div class=""><font face="Menlo" class=""> </font></div><div class=""><font face="Menlo" class=""> private var _instance: _Cluster</font></div><div class=""><font face="Menlo" class=""> </font></div><div class=""><font face="Menlo" class=""> init(name: String) {</font></div><div class=""><font face="Menlo" class=""> _instance = _ClusterString(name: name)</font></div><div class=""><font face="Menlo" class=""> }</font></div><div class=""><font face="Menlo" class=""> </font></div><div class=""><font face="Menlo" class=""> init(value: Int) {</font></div><div class=""><font face="Menlo" class=""> _instance = _ClusterValue(value: value)</font></div><div class=""><font face="Menlo" class=""> }</font></div><div class=""><font face="Menlo" class=""> </font></div><div class=""><font face="Menlo" class=""> func description() -> String {</font></div><div class=""><font face="Menlo" class=""> return _instance.description()</font></div><div class=""><font face="Menlo" class=""> }</font></div><div class=""><font face="Menlo" class="">}</font></div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class="">private class _ClusterString: _Cluster {</font></div><div class=""><font face="Menlo" class=""> private var name: String</font></div><div class=""><font face="Menlo" class=""> init(name: String) { <a href="http://self.name/" target="_blank" class="">self.name</a> = name }</font></div><div class=""><font face="Menlo" class=""> func description() -> String {</font></div><div class=""><font face="Menlo" class=""> return "_ClusterString: \(name)"</font></div><div class=""><font face="Menlo" class=""> }</font></div><div class=""><font face="Menlo" class="">}</font></div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class="">private class _ClusterValue: _Cluster {</font></div><div class=""><font face="Menlo" class=""> private var value: Int</font></div><div class=""><font face="Menlo" class=""> init(value: Int) { self.value = value }</font></div><div class=""><font face="Menlo" class=""> func description() -> String {</font></div><div class=""><font face="Menlo" class=""> return "_ClusterValue: \(value)"</font></div><div class=""><font face="Menlo" class=""> }</font></div><div class=""><font face="Menlo" class="">}</font></div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class="">let s = Cluster(name: "a string")</font></div><div class=""><font face="Menlo" class="">s.description()</font></div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class="">let v = Cluster(value: 12)</font></div><div class=""><font face="Menlo" class="">v.description()</font></div></blockquote><div class=""><br class=""></div><div class=""><br class=""></div><div class="">The implementation is different from how ObjC implements class clusters, but the end result is nearly identical in functionality. If Swift had a form of function redirection, this pattern could be supported with less boiler-plate. However, I don’t believe this proposal is necessary to support class clusters.</div><div class=""><br class=""></div><div class="">-David</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div class=""><div class=""><div class="">On Dec 7, 2015, at 12:19 PM, Riley Testut via swift-evolution <<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>> wrote:</div><br class=""></div></div><div class=""><div class=""><div class=""><div dir="ltr" class=""><span class="">Happy Monday everyone!</span><div class=""><br class=""></div><div class="">I wrote up a prototype proposal, which is probably best viewed on GitHub (<a href="https://github.com/rileytestut/swift-proposals/blob/master/class-cluster.md" target="_blank" class="">https://github.com/rileytestut/swift-proposals/blob/master/class-cluster.md</a>). But for convenience, I’ve included it in this email body as well. Hopefully someone else thinks this would be an idea worth considering :-) </div><div class=""><br class=""></div><div class=""><div class=""><b class="">## Introduction</b></div><div class=""><br class=""></div><div class="">Throughout its frameworks, Apple makes use of the “class cluster” pattern as a means to separate the public API out from the (potentially complex) internal representations of the data. Clients of the API simply use the public API, while under the hood a different implementation is chosen to most efficiently represent the provided initialization parameter values.</div><div class=""><br class=""></div><div class="">Unfortunately, because initializers in Swift are not methods like in Objective-C, there is no way to specify what the actual return value should be (short of returning nil for failable initializers). This makes it *impossible* to actually implement the class cluster pattern in Swift.</div><div class=""><br class=""></div><div class=""><b class="">## Motivation</b></div><div class=""><br class=""></div><div class="">While developing my own Swift framework, I found myself wanting to provide a similar functionality. For the client of said framework, I wanted them to be able to create an instance of an essentially abstract class, and be returned a private subclass instance suited best for handling whatever input initialization parameters they provided. It didn’t make sense given the circumstances to ask the user to decide which class would be the best representation of the data; it should “just work”.</div><div class=""><br class=""></div><div class="">Additionally, the class cluster pattern can make backwards compatibility significantly easier; instead of littering your code with branches for different versions of an OS, you could instead have one if/switch statement to determine the appropriate subclass for the current OS you’re running on. This allows the developer to trivially keep legacy code for older platforms while taking advantage of new APIs/designs, and also without changing *any* client code. An example of the class cluster pattern being used for this reason can be seen here: <a href="http://www.xs-labs.com/en/blog/2013/06/18/ios7-new-ui-strategies/" target="_blank" class="">http://www.xs-labs.com/en/blog/2013/06/18/ios7-new-ui-strategies/</a></div><div class=""><br class=""></div><div class=""><b class="">## Proposed solution</b></div><div class=""><br class=""></div><div class="">I propose that we allow for implementation of the class cluster pattern by providing a way to (at run time) specify the actual type that should be initialized depending on the provided initialization parameters.</div><div class=""><br class=""></div><div class=""><b class="">## Detailed design</b></div><div class=""><br class=""></div><div class=""><u class="">Introduce a new class method that can return an appropriate type that should be used for initialization, depending on the provided initialization parameters.</u></div><div class=""><br class=""></div><div class="">This is what I believe to be the most clean solution, and with (assumedly) minimal impact on the existing nature of Swift’s initialization process. To ensure this remains safe, the only types allowed to be returned should be subclasses of the parent class (such as returning a __NSArrayI for NSArray). Notably, beyond this method, everything else remains the same; all this does is change what class the initializer is called on initially.</div><div class=""><br class=""></div><div class="">Here is an ideal implementation gist:</div><div class=""><a href="https://gist.github.com/rileytestut/0e6e80d3f22b845502e7" target="_blank" class="">https://gist.github.com/rileytestut/0e6e80d3f22b845502e7</a><br class=""></div><div class=""><br class=""></div><div class=""><b class="">## Impact on existing code</b></div><div class=""><br class=""></div><div class="">There will be zero impact on existing code; if the proposed class method is not implemented, then it will default to simply initializing the “base” class, as it always has.</div><div class=""><br class=""></div><div class=""><b class="">## Alternatives considered</b></div><div class=""><br class=""></div><div class=""><u class="">Allow for return values in initializers</u></div><div class=""><br class=""></div><div class="">This is essentially how most class cluster patterns are implemented in Objective-C. Inside the init method, the class inspects the provided parameters, then assigns self to an instance of the appropriate subclass. Unfortunately, this is wasteful; memory is allocated for the base class, and then subsequently replaced with new memory allocated for the appropriate base class. More importantly though, the whole process can be complicated; it can be very easy to make an infinite recursive loop by calling [super init] in the subclass, which then assigns self to a new instance of the subclass, which then calls [super init]…etc. </div><div class=""><br class=""></div><div class="">tl;dr; this method would work, but would be somewhat inconvenient to implement.</div><div class=""><br class=""></div><div class=""><u class="">Class function to return appropriate instance</u></div><div class=""><br class=""></div><div class="">This is probably the simplest approach: simply make a class function that returns an instance of the appropriate class given a few input parameters. This totally works, but it means consumers of the API have to remember to use the class method instead of the initializer. Even if all initializers for the class were marked private, it would be strange to have the dissonance between using initializers and class methods to instantiate types in code. The consumer should not have to know about *any* of the implementation details; everything should “just work”. Forcing them to use alternative means to instantiate objects breaks this philosophy, IMO.</div><div class=""><br class=""></div><div class=""><u class="">Derive from Objective-C base class</u></div><div class=""><br class=""></div><div class="">Another option is to simply derive from an Objective-C base class, and this is actually what I am doing right now in my framework. Unfortunately, there is one significant drawback: because the initialization is happening in Objective-C, you can only provide Objective-C compatible types for the initialization parameters (so no Swift structs for you!). Additionally, this (obviously) means whatever code is using it is limited to systems with Objective-C support, so it is not as portable as a pure-Swift solution.</div><div class=""><br class=""></div></div></div></div></div><span class=""><img src="https://u2002410.ct.sendgrid.net/wf/open?upn=nE9rxSXA5G4kxsTVkgv43pXkLx-2B36P-2BPNJufHeY0dgfJy-2FEEfVU-2BGToZLkQbIjT-2FmOX-2B0abbKs-2FNDhBof5llBhSXMDYkcFgZBmwFO5wLwPTL8KadicwG6lI2micqenfwRvVSTW7-2FnhOY7UX6sDSNiHaAzcvFhpXPsWcRQmJapRCh1CUj288XlYofAjeokRgvWvBjc5AnNR9s70BYOPNy3w-3D-3D" alt="" width="1" height="1" border="0" class="" style="min-height: 1px !important; width: 1px !important; border-width: 0px !important; margin: 0px !important; padding: 0px !important;"> _______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></span></div></blockquote></div><br class=""><img src="https://u2002410.ct.sendgrid.net/wf/open?upn=1p9Jer2O6jVE9KWvo-2B9iUaEyN8slp4IizyiLwsfp54MEtNNixfjCN5oS2qp23gBGzYr9p2j3OPnToUsR4fDJzwhG4UgoPpQIyz3ThMe5BFaVEWwyRP4QmlweGv64ZRlcN7q3XvEwZNQE7rJwL6ag-2FRP6jZIOjBKsL8ee-2FCdG2UXrFUoxMetotpyZzIme6JDcLqCHHlpxguLrm93sVWCgPyeLquA2VXyROmigBL69WPA-3D" alt="" width="1" height="1" border="0" class="" style="min-height: 1px !important; width: 1px !important; border-width: 0px !important; margin: 0px !important; padding: 0px !important;"></div><br class="">_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></blockquote></div></div></div></blockquote></div></div></div></blockquote></div></div></div></div></blockquote></div></div></div></blockquote></div></body></html>