The reason for the additional “factory” keyword would be to differentiate it from other initializers because it actually “returned" a value. For the record, I am entirely in support of modifying convenience initializers to return instances directly; I assumed (incorrectly it seems!) that the ability to return directly from an initializer was intentionally left out, for whatever reason. I agree using the convenience initializer syntax with an explicit return type would be a better approach, and would be more in-line with what you can do with initializers in Objective-C :-)
If this is already implemented in the compiler, I would love to certainly push this idea forward! I genuinely believe this could add great value to the language, without changing the fundamentals too much. > On Dec 17, 2015, at 6:25 PM, Chris Lattner <[email protected]> wrote: > >> >> 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] <mailto:[email protected]> >> https://lists.swift.org/mailman/listinfo/swift-evolution >> <https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
