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

ilya ilya.nikokoshev at gmail.com
Mon Dec 7 17:39:06 CST 2015


Some thoughts:

1 "self =" is better in inits because of a common pattern of configuring an
object in the second init stage

2 since there is already an existing syntax for protocol implementation
functions, the role of init keyword is basically to stand for "empty
function name" syntax. This sounds interesting.

3 you can also add init to the protocol (with Self return value and
required keyword) for some interesting effects.

4 final init, not class init (because init is already called on the class):

class BaseClass {
init(x: ...) -> Self // regular, inheritable init, Self can be omitted
final init(y:...) -> Self // Self always = BaseClass, can return Derived()

5 yes, that would nicely work with ObjC, even if that was not the original
goal :)

On Tue, Dec 8, 2015 at 02:24 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/e9905b08/attachment.html>


More information about the swift-evolution mailing list