[swift-evolution] Proposal: Allow class cluster pattern via dynamic initializer return type

Austin Zheng austinzheng at gmail.com
Mon Dec 7 20:17:08 CST 2015


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.

Austin

On Mon, Dec 7, 2015 at 3:24 PM, Brent Royal-Gordon via swift-evolution <
swift-evolution at swift.org> wrote:

> > 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.
> >
> > 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.
>
> 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.
>
> Here’s my thinking.
>
> 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.
>
> Here’s what I think Swift should support:
>
>         protocol HTTPParameterListType {
>                 var all: DictionaryLiteral<String, Strong> { get }
>                 subscript (name: String) -> [String] { get }
>         }
>
>         // Various implementations include:
>         struct JSONParameterList: HTTPParameterList {...}
>         struct MultipartParameterList: HTTParameterList {…}
>         struct URLEncodedFormParameterList: HTTPParameterList {…}
>         struct QueryParameterList: HTTPParameterList {…}
>
>         extension HTTPParameterListType {
>                 protocol init(request: NSHTTPRequest, bodyData: NSData)
> throws {
>                         switch
> request.valueForHTTPHeaderField(“Content-Type”).map({ MIMEType(rawValue:
> $0) }) {
>                         case .JSON?:
>                                 return try JSONParameterList(data:
> bodyData)
>
>                         case .MultipartFormData?:
>                                 return try MultipartParameterList(data:
> bodyData)
>
>                         case .URLEncodedForm?:
>                                 return try
> URLEncodedFormParameterList(data: bodyData)
>
>                         default:
>                                 return try QueryParameterList(request:
> request)
>                         }
>                 }
>         }
>
>         // Usage:
>         self.parameters = HTTPParameterListType(request: request,
> bodyData: data)
>
> 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.
>
> 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.
>
> 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.
>
> --
> Brent Royal-Gordon
> Architechies
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151207/c71d7be3/attachment.html>


More information about the swift-evolution mailing list