> On Dec 18, 2015, at 8:15 AM, Thorsten Seitz <[email protected]> wrote: > > Now I'm confused: I thought the idea should enable class clusters, i.e. > allowing AbstractBaseClass(42) to return something with the *dynamic* type of > ConcreteImplementation but still the static type of AbstractBaseClass. > Otherwise I would just call ConcreteImplementation(42) if I wanted something > of that static type.
Got it. If that is the case, then yes, something like a “factory init” makes sense to me. It is unfortunate that such a thing would make the swift initializer model even MORE complex :-) but it is probably still the right way to go. -Chris > > -Thorsten > >> Am 18.12.2015 um 01:25 schrieb Chris Lattner via swift-evolution >> <[email protected]>: >> >> >>> On Dec 17, 2015, at 1:41 PM, Riley Testut via swift-evolution >>> <[email protected]> wrote: >>> >>> Recently, I proposed the idea of adding the ability to implement the "class >>> cluster" pattern from Cocoa (Touch) in Swift. However, as we discussed it >>> and came up with different approaches, it evolved into a functionality that >>> I believe is far more beneficial to Swift, and subsequently should be the >>> focus of its own proposal. So here is the improved (pre-)proposal: >>> >>> # Factory Initializers >>> >>> The "factory" pattern is common in many languages, including Objective-C. >>> Essentially, instead of initializing a type directly, a method is called >>> that returns an instance of the appropriate type determined by the input >>> parameters. Functionally this works well, but ultimately it forces the >>> client of the API to remember to call the factory method instead, rather >>> than the type's initializer. This might seem like a minor gripe, but given >>> that we want Swift to be as approachable as possible to new developers, I >>> think we can do better in this regard. >>> >>> Rather than have a separate factory method, I propose we build the factory >>> pattern right into Swift, by way of specialized “factory initializers”. The >>> exact syntax was proposed by Philippe Hausler from the previous thread, and >>> I think it is an excellent solution: >>> >>> class AbstractBase { >>> public factory init(type: InformationToSwitchOn) { >>> return ConcreteImplementation(type) >>> } >>> } >>> >>> class ConcreteImplementation : AbstractBase { >>> >>> } >> >> I’m confused, isn’t this already handled by “convenience” initializers? >> >> What we lack now is the ability to use the AbstractBase(42) syntax the >> produce something with a static type of ConcreteImplementation. This is >> something expressible in Objective-C, and something that Swift can currently >> import into Objective-C, but that you can’t write directly in Swift code >> right now. >> >> The approach that I would suggest is a simple extension of the grammar, to >> allow "-> T” on a convenience initializer. In this case, you could write: >> >> >> class AbstractBase { >> convenience init(type: InformationToSwitchOn) -> ConcreteImplementation { >> return ConcreteImplementation(type) >> } >> >> and then "AbstractBase(stuff)” would produce a value with the static type of >> ConcreteImplementation. This syntax is already produced by the AST printer >> for imported ObjC stuff, so we have much of the mechanics for this already >> in the compiler. It would be great to see someone push this forward! >> >> -Chris >> >> >> >> >>> >>> Why exactly would this be useful in practice? In my own development, I’ve >>> come across a few places where this would especially be relevant: >>> >>> ## Class Cluster/Abstract Classes >>> This was the reasoning behind the original proposal, and I still think it >>> would be a very valid use case. The public superclass would declare all the >>> public methods, and could delegate off the specific implementations to the >>> private subclasses. Alternatively, this method could be used as an easy way >>> to handle backwards-compatibility: rather than litter the code with >>> branches depending on the OS version, simply return the OS-appropriate >>> subclass from the factory initializer. Very useful. >>> >>> ## Protocol Initializers >>> Proposed by Brent Royal-Gordon, we could use factory initializers with >>> protocol extensions to return the appropriate instance conforming to a >>> protocol for the given needs. Similar to the class cluster/abstract class >>> method, but can work with structs too. This would be closer to the factory >>> method pattern, since you don’t need to know exactly what type is returned, >>> just the protocol it conforms to. >>> >>> ## Initializing Storyboard-backed View Controller >>> This is more specific to Apple Frameworks, but having factory initializers >>> could definitely help here. Currently, view controllers associated with a >>> storyboard must be initialized from the client through a factory method on >>> the storyboard instance (storyboard. >>> instantiateViewControllerWithIdentifier()). This works when the entire flow >>> of the app is storyboard based, but when a single storyboard is used to >>> configure a one-off view controller, having to initialize through the >>> storyboard is essentially use of private implementation details; it >>> shouldn’t matter whether the VC was designed in code or storyboards, >>> ultimately a single initializer should “do the right thing” (just as it >>> does when using XIBs directly). A factory initializer for a View Controller >>> subclass could handle the loading of the storyboard and returning the >>> appropriate view controller. >>> >>> Here are some comments from the previous thread that I believe are still >>> relevant: >>> >>> >>>> On Dec 9, 2015, at 1:06 PM, Philippe Hausler <[email protected]> wrote: >>>> >>>> I can definitely attest that in implementing Foundation we could have much >>>> more idiomatic swift and much more similar behavior to the way Foundation >>>> on Darwin actually works if we had factory initializers. >>> >>> >>>> On Dec 7, 2015, at 5:24 PM, Brent Royal-Gordon <[email protected]> >>>> wrote: >>>> >>>> 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. >>> >>> >>> I’d love to hear everyone’s thoughts on this! >>> >>> Best, >>> Riley Testut >>> _______________________________________________ >>> swift-evolution mailing list >>> [email protected] >>> https://lists.swift.org/mailman/listinfo/swift-evolution >> >> _______________________________________________ >> swift-evolution mailing list >> [email protected] >> https://lists.swift.org/mailman/listinfo/swift-evolution _______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
