<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="">While I agree this solves the issue, I feel this enhancement could be useful for far more than replicating the simple class cluster pattern. Because of this, I think might make a new proposal focusing on protocol initializers, and have the class cluster pattern be just one example of an advantage. Are there any other problems this might be able to solve?<div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Dec 7, 2015, at 6:17 PM, Austin Zheng &lt;<a href="mailto:austinzheng@gmail.com" class="">austinzheng@gmail.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">I really like the idea of having a 'protocol initializer' which transparently chooses an appropriate concrete type to return. Once recursive protocol conformance and conditional conformance has been implemented, you'd be able to work with type "aggregates" (imagine JSON or plist types implemented exclusively as protocol conformances on existing types) almost completely in terms of the generic protocol interface.<div class=""><br class=""></div><div class="">Austin</div></div><div class="gmail_extra"><br class=""><div class="gmail_quote">On Mon, Dec 7, 2015 at 3:24 PM, Brent Royal-Gordon via swift-evolution <span dir="ltr" class="">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>&gt;</span> wrote:<br class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">&gt; 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.<br class="">
&gt;<br class="">
&gt; 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.<br class="">
<br class="">
</span>I’d actually like to put Objective-C interop aside for a moment. There are many class clusters in Objective-C, but most of them are things you rarely need to subclass yourself. When was the last time you wrote an NSArray subclass? What’s more interesting to me is how we can provide a similar native Swift pattern.<br class="">
<br class="">
Here’s my thinking.<br class="">
<br class="">
First of all, we call them “class” clusters, but there’s no reason this should be only for classes. A “class cluster” is basically a single API which offers access to many different implementations of an interface. The phrase “many different implementations of an interface” is a hint that we should be thinking about protocols.<br class="">
<br class="">
Here’s what I think Swift should support:<br class="">
<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; protocol HTTPParameterListType {<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var all: DictionaryLiteral&lt;String, Strong&gt; { get }<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; subscript (name: String) -&gt; [String] { get }<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; }<br class="">
<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; // Various implementations include:<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; struct JSONParameterList: HTTPParameterList {...}<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; struct MultipartParameterList: HTTParameterList {…}<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; struct URLEncodedFormParameterList: HTTPParameterList {…}<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; struct QueryParameterList: HTTPParameterList {…}<br class="">
<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; extension HTTPParameterListType {<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; protocol init(request: NSHTTPRequest, bodyData: NSData) throws {<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; switch request.valueForHTTPHeaderField(“Content-Type”).map({ MIMEType(rawValue: $0) }) {<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case .JSON?:<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return try JSONParameterList(data: bodyData)<br class="">
<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case .MultipartFormData?:<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return try MultipartParameterList(data: bodyData)<br class="">
<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; case .URLEncodedForm?:<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return try URLEncodedFormParameterList(data: bodyData)<br class="">
<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; default:<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return try QueryParameterList(request: request)<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; }<br class="">
<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; // Usage:<br class="">
&nbsp; &nbsp; &nbsp; &nbsp; self.parameters = HTTPParameterListType(request: request, bodyData: data)<br class="">
<br class="">
A `protocol init` in a protocol extension creates an initializer which is *not* applied to types conforming to the protocol. Instead, it is actually an initializer on the protocol itself. `self` is the protocol metatype, not an instance of anything. The provided implementation should `return` an instance conforming to (and implicitly casted to) the protocol. Just like any other initializer, a `protocol init` can be failable or throwing.<br class="">
<br class="">
Unlike other initializers, Swift usually won’t be able to tell at compile time which concrete type will be returned by a protocol init(), reducing opportunities to statically bind methods and perform other optimization tricks. Frankly, though, that’s just the cost of doing business. If you want to select a type dynamically, you’re going to lose the ability to aggressively optimize calls to the resulting instance.<br class="">
<br class="">
Perhaps this feature can then be extended back to classes, with a `class init` being an un-inherited initializer which uses `return` to give the caller a new object. `self` would be the class object, and only class variables and methods would be callable from it. But like I said, I’m not particularly interested in Objective-C interop right now.<br class="">
<span class="HOEnZb"><font color="#888888" class=""><br class="">
--<br class="">
Brent Royal-Gordon<br class="">
Architechies<br class="">
</font></span><div class="HOEnZb"><div class="h5"><br class="">
_______________________________________________<br class="">
swift-evolution mailing list<br class="">
<a href="mailto:swift-evolution@swift.org" 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><br class="">
</div></div></blockquote></div><br class=""></div>
</div></blockquote></div><br class=""></div></body></html>