Hello again everyone! Just an update, I did submit the PR about a week ago, and you can check it out here: https://github.com/apple/swift-evolution/pull/247
As far as I know, now we wait until a core team member reviews the PR, and either suggests changes, or accepts it and initiates a review. Of course, if this is incorrect, please let me know so I can do whatever next steps there are :-) Thanks again for all the contributions to this proposal, hope we see it get approved soon! Riley > On Apr 4, 2016, at 11:58 AM, Riley Testut <[email protected]> wrote: > > Hey all! > > Just updated the proposal with all the recent changes, and you can check it > here: > https://github.com/rileytestut/swift-evolution/blob/master/proposals/NNNN-factory-initializers.md > > <https://github.com/rileytestut/swift-evolution/blob/master/proposals/NNNN-factory-initializers.md> > > Planning on submitting the PR later tonight, so please let me know if you > have any last minute feedback! > Riley > >> On Mar 30, 2016, at 1:35 PM, Jonathan Hull <[email protected] >> <mailto:[email protected]>> wrote: >> >> Probably ‘no' in this proposal to keep things simple. >> >> Long term, I would like overriding of the factory init to be the mechanism >> for a post-hoc extendable factory. Disallowing it now probably makes that >> easier in the future. >> >> Thanks, >> Jon >> >> >>> On Mar 30, 2016, at 1:20 PM, Riley Testut <[email protected] >>> <mailto:[email protected]>> wrote: >>> >>> Another point to consider: should factory initializers be able to be >>> overridden by subclasses? I vote no, just as you can't override convenience >>> initializers. >>> >>> On Mar 30, 2016, at 3:50 AM, Jonathan Hull <[email protected] >>> <mailto:[email protected]>> wrote: >>> >>>> Yeah. I was thinking we would want to mirror the convenience initializer >>>> syntax, but I am completely ok with this as well. Honestly this is the >>>> syntax I first tried to use in convenience inits while learning swift, and >>>> I would love to see that migrate to something like this. My only worry >>>> would be that people would be confused on when to use ClassName() and when >>>> to use self.init(). Best to choose one and stick with it. >>>> >>>> Thanks, >>>> Jon >>>> >>>>> On Mar 30, 2016, at 3:36 AM, Riley Testut <[email protected] >>>>> <mailto:[email protected]>> wrote: >>>>> >>>>> If we are to enforce a different type signature for factory initializers >>>>> vs required/convenience initializers (which would greatly simplify this >>>>> issue), if I’m understanding correctly, there shouldn’t be a need to be >>>>> able to “return” self.init(), right? Because you could do this instead: >>>>> >>>>> public class ConcreteBase { >>>>> >>>>> private init(type2: InformationToSwitchOn) { >>>>> //Default implementation here >>>>> } >>>>> >>>>> public factory init (type: InformationToSwitchOn) { >>>>> if … { >>>>> return SpecialSubclass(type) //Handle a special case >>>>> with a more efficient implementation >>>>> } >>>>> return ConcreteBase(type) //Handle the general case with the >>>>> main class >>>>> } >>>>> } >>>>> >>>>> class SpecialSubclass : ConcreteBase {} >>>>> >>>>>> On Mar 30, 2016, at 3:30 AM, Jonathan Hull <[email protected] >>>>>> <mailto:[email protected]>> wrote: >>>>>> >>>>>> Doh! >>>>>> >>>>>> Sorry, typed that up in mail while working on something else at the same >>>>>> time. We shouldn’t allow an init with the same signature. self.init() >>>>>> could be called with different parameters. Trying to call the factory >>>>>> method from the factory method should generate an error. >>>>>> >>>>>> We probably also want to disallow having an init with the same signature >>>>>> in subclasses as well (we could pass the same info with different >>>>>> parameter names) as a subclass which doesn’t override it would again be >>>>>> calling the factory method. Ultimately, I would like to see the ability >>>>>> to override the factory method with the behavior I described earlier… >>>>>> but that is for a later proposal. >>>>>> >>>>>> Basically we should be able to return anything which adheres to the >>>>>> type, so we are free to use other initializers on the class/subclasses. >>>>>> >>>>>> Thanks, >>>>>> Jon >>>>>> >>>>>> >>>>>>> On Mar 30, 2016, at 3:10 AM, Riley Testut <[email protected] >>>>>>> <mailto:[email protected]>> wrote: >>>>>>> >>>>>>> Ah, good catch. Would that be confusing as to whether self.init() would >>>>>>> lead to an infinite loop, or call the required initializer? Unlike >>>>>>> convenience initializers, factory initializers might have the same >>>>>>> signature as the required ones. >>>>>>> >>>>>>>> On Mar 30, 2016, at 2:52 AM, Jonathan Hull <[email protected] >>>>>>>> <mailto:[email protected]>> wrote: >>>>>>>> >>>>>>>> Agreed. I would like to see what I was referring to as “stage 1” in >>>>>>>> this proposal, and we can (hopefully) add on a full solution over >>>>>>>> time. (I just wanted to make sure we considered those cases so we >>>>>>>> didn’t block future improvements) >>>>>>>> >>>>>>>> Looking at the proposal, my only contention would be that we should >>>>>>>> also allow self.init() to be called from the factory init (similar to >>>>>>>> a convenience init). It could still be used with an AbstractBase as >>>>>>>> shown in your example (especially when dealing with protocols), but it >>>>>>>> shouldn’t force us to be abstract in the class case. >>>>>>>> >>>>>>>> In other words, we should also be able to do the following: >>>>>>>> >>>>>>>> public class ConcreteBase { >>>>>>>> >>>>>>>> private init(type: InformationToSwitchOn) { >>>>>>>> //Default implementation here >>>>>>>> } >>>>>>>> >>>>>>>> public factory init (type: InformationToSwitchOn) { >>>>>>>> if … { >>>>>>>> return SpecialSubclass(type) //Handle a >>>>>>>> special case with a more efficient implementation >>>>>>>> } >>>>>>>> return self.init(type) //Handle the general case with >>>>>>>> the main class >>>>>>>> } >>>>>>>> } >>>>>>>> >>>>>>>> class SpecialSubclass : ConcreteBase {} >>>>>>>> >>>>>>>> >>>>>>>> >>>>>>>> The behavior should simply be that we can return any init’d object >>>>>>>> that conforms to the given type. >>>>>>>> >>>>>>>> Thanks, >>>>>>>> Jon >>>>>>>> >>>>>>>> >>>>>>>>> On Mar 30, 2016, at 2:20 AM, Riley Testut <[email protected] >>>>>>>>> <mailto:[email protected]>> wrote: >>>>>>>>> >>>>>>>>> Ultimately, while these are good points, I feel the full mechanism >>>>>>>>> for class clusters belong in a separate proposal. The focus for this >>>>>>>>> one I believe should be the underlying mechanism of factory >>>>>>>>> initializers; should that be approved, then we can focus on adding >>>>>>>>> additional features on top of it. >>>>>>>>> >>>>>>>>> That being said, I’ve written up essentially a final version of the >>>>>>>>> proposal, which you can find here: >>>>>>>>> https://github.com/rileytestut/swift-evolution/blob/master/proposals/NNNN-factory-initializers.md >>>>>>>>> >>>>>>>>> <https://github.com/rileytestut/swift-evolution/blob/master/proposals/NNNN-factory-initializers.md>. >>>>>>>>> Assuming everyone is happy with it, I’ll send a pull request in the >>>>>>>>> next few days to the main-repo. But please, give any last minute >>>>>>>>> feedback now! >>>>>>>>> >>>>>>>>>> On Mar 24, 2016, at 5:12 PM, Jonathan Hull <[email protected] >>>>>>>>>> <mailto:[email protected]>> wrote: >>>>>>>>>> >>>>>>>>>> Comments inline. >>>>>>>>>> >>>>>>>>>>> On Mar 24, 2016, at 12:10 AM, Riley Testut <[email protected] >>>>>>>>>>> <mailto:[email protected]>> wrote: >>>>>>>>>>> >>>>>>>>>>> While I do believe your proposed additions have their benefits, my >>>>>>>>>>> gut tells me this is too large a change to Swift for an arguably >>>>>>>>>>> small gain. For this proposal, I'm wanting to keep the change as >>>>>>>>>>> minimalistic as possible, while still providing enough flexibility >>>>>>>>>>> and use cases to warrant it. >>>>>>>>>> >>>>>>>>>> I can definitely see the argument that extensibility is out of scope >>>>>>>>>> for Swift 3, but I do want to make sure that it is possible for us >>>>>>>>>> to have extensibility in the future (that we don’t block ourselves >>>>>>>>>> from doing it). >>>>>>>>>> >>>>>>>>>> I strongly disagree that the gain is small. One of the core >>>>>>>>>> benefits of both Swift/ObjC (and now POP) is the ability to extend >>>>>>>>>> things post-hoc, without access to the original code. >>>>>>>>>> >>>>>>>>>> I often write libraries & SDKs, so the users of my code don't have >>>>>>>>>> access to the original code. I guess extensibility is less >>>>>>>>>> necessary when you control the entire codebase, but you still have >>>>>>>>>> to refactor your factory whenever you subclass (or adhere to a >>>>>>>>>> protocol), which I find problematic. >>>>>>>>>> >>>>>>>>>> This is something I run into a lot while writing actual code, so it >>>>>>>>>> isn’t just a theoretical concern. >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>>> Interesting you bring up the registering of subclasses, as that is >>>>>>>>>>> similar to the very original proposal, and actually similar to what >>>>>>>>>>> I'm doing in my own app. Effectively, I have an Objective-C base >>>>>>>>>>> class, and in +load it dynamically finds all subclasses using the >>>>>>>>>>> Objective-C runtime, and stores a reference to them. Then in the >>>>>>>>>>> initializer, it returns the appropriate subclass based on the >>>>>>>>>>> initialization parameters. This was my solution to the superclass >>>>>>>>>>> not having to explicitly know each individual subclass. >>>>>>>>>>> >>>>>>>>>>> Using factory initializers, however, this pattern could be used in >>>>>>>>>>> pure Swift, albeit with some minor modifications. At program start, >>>>>>>>>>> the program could register subclasses with the superclass, and then >>>>>>>>>>> in the initializer would simply return the appropriate subclass >>>>>>>>>>> (similar to NSURLProtocol, I believe). >>>>>>>>>> >>>>>>>>>> Yes, I have also used load in this way in ObjC. In Swift, I think >>>>>>>>>> the compiler could easily build an array/table of the overloads of >>>>>>>>>> factory inits. This avoids having to register explicitly (the >>>>>>>>>> declaration itself implies intent to register), and doesn’t take up >>>>>>>>>> any cycles during execution. >>>>>>>>>> >>>>>>>>>> I ran into the problem of when to register the other day in a >>>>>>>>>> current project, as Swift doesn’t have an equivalent to +load that I >>>>>>>>>> am aware of. I had to settle for something of a hack which gets >>>>>>>>>> called on first use… but it was only a partial solution which worked >>>>>>>>>> in that particular case. How do the swift classes/enums/structs get >>>>>>>>>> called to register themselves? >>>>>>>>>> >>>>>>>>>> We may want to propose adding a +load equivalent for Swift types, >>>>>>>>>> since it does come up occasionally. It is one of those things which >>>>>>>>>> you don’t need often, but when you do, you really need it. >>>>>>>>>> Ironically, this was one of the uses of the original feature I >>>>>>>>>> talked about earlier (we used it to provide the equivalent of +load, >>>>>>>>>> awakeFromNib, etc… in the language). >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> >>>>>>>>>>> As for rationale for protocol (factory) initializers, a common >>>>>>>>>>> pattern I've come across when developing my internal frameworks is >>>>>>>>>>> to design a protocol, and then to provide a default implementation >>>>>>>>>>> of the protocol with a type (typically a struct). I feel this >>>>>>>>>>> relationship could be bridged easier by simply returning this type >>>>>>>>>>> from a protocol initializer, which could even potentially allow me >>>>>>>>>>> to declare the actual type as private, so for all intents and >>>>>>>>>>> purposes the client does simply get an initialized protocol object >>>>>>>>>>> (similar in part to creating an anonymous class conforming to a >>>>>>>>>>> protocol in Java). >>>>>>>>>> >>>>>>>>>> I strongly agree that we should have factory initializers for >>>>>>>>>> protocols for the reasons you state here, plus many others. It just >>>>>>>>>> seems like a natural fit. >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> I would like to see a 3 stage approach: >>>>>>>>>> >>>>>>>>>> Stage 1: Declaring an init as “factory” allows you to return any >>>>>>>>>> fully inited object which fits the type (including calling self.init >>>>>>>>>> like a convenience init would and then returning it). If the init is >>>>>>>>>> failable, you can also return nil. This works both on classes and >>>>>>>>>> protocols. >>>>>>>>>> >>>>>>>>>> Stage 2: The compiler builds a table of the overrides of a given >>>>>>>>>> factory init, and there is some syntax to call them (e.g. “let sub = >>>>>>>>>> subclasses.init(value)”) such that the first one to return non-nil >>>>>>>>>> is the return value to that call. Thorsten’s depth first + >>>>>>>>>> alphabetical ordering would be adequate to make the behavior >>>>>>>>>> predictable. Again, this should work for both classes and >>>>>>>>>> protocols. (I am open to better ideas for syntax/naming) >>>>>>>>>> >>>>>>>>>> Stage 3: We allow greater control over the ordering in the table. >>>>>>>>>> This still needs thought both on syntax and method. Something >>>>>>>>>> similar to operator precedence (or autolayout priority) would work >>>>>>>>>> in a pinch, but isn’t super elegant. In practice, it might be enough >>>>>>>>>> just to be able to declare that something needs to be before/after a >>>>>>>>>> specific subclass in the list. >>>>>>>>>> >>>>>>>>>> >>>>>>>>>> Note: A slightly different approach to stage 2 (for classes) might >>>>>>>>>> have only the direct subclasses in the table, and then the >>>>>>>>>> subclasses have the option to call off to their own subclasses in >>>>>>>>>> the same manner if desired. This has the tradeoff that each level >>>>>>>>>> needs to plan for extensibility (i.e. you can’t override something >>>>>>>>>> which wasn’t expecting to be subclassed), but I do like how it >>>>>>>>>> simplifies the model a bit. >>>>>>>>>> >>>>>>>>>> I have a feeling that the proper syntax for stages 2/3 may become >>>>>>>>>> more obvious once the design work around mixins/protocols+storage >>>>>>>>>> gets done. It may just fall out of the disambiguation syntax... >>>>>>>>>> >>>>>>>>>> Thanks, >>>>>>>>>> Jon >>>>>>>>>> >>>>>>>>>>> On Mar 22, 2016, at 5:21 PM, Jonathan Hull <[email protected] >>>>>>>>>>> <mailto:[email protected]>> wrote: >>>>>>>>>>> >>>>>>>>>>>> >>>>>>>>>>>> Yes and No. >>>>>>>>>>>> Yes, because this is a problem I run into all the time, and I >>>>>>>>>>>> really want swift to have a solution for it. I especially like >>>>>>>>>>>> Brent’s idea of a protocol init. >>>>>>>>>>>> No, because I have gotten a bit greedy. I want us to take a step >>>>>>>>>>>> back and look at the underlying problem to see if we can come up >>>>>>>>>>>> with something which completely solves it… and I think factories >>>>>>>>>>>> get us only part way there. Let’s take a moment and see if we can >>>>>>>>>>>> create something uniquely swift before we copy/paste existing >>>>>>>>>>>> solutions. >>>>>>>>>>>> Think about Cocoa’s class clusters for a moment. I love them, but >>>>>>>>>>>> they are a pain to subclass. To the level where any beginning >>>>>>>>>>>> Cocoa instruction tells you explicitly not to subclass them. >>>>>>>>>>>> Similarly, even in my own factories, they are always a pain to >>>>>>>>>>>> extend. >>>>>>>>>>>> I want our factory inits to be extensible by default. >>>>>>>>>>>> >>>>>>>>>>>> By extensible, I mean that I want to be able to add a new subclass >>>>>>>>>>>> (or a new entity satisfying a protocol), and have it come out of >>>>>>>>>>>> the factory when appropriate without editing the base class! >>>>>>>>>>>> Madness, I know, but: >>>>>>>>>>>> 1) I may not have access to the source of the base class (e.g. >>>>>>>>>>>> Cocoa Collections) >>>>>>>>>>>> 2) I always feel a bit dirty giving the base class knowledge of >>>>>>>>>>>> it’s subclasses >>>>>>>>>>>> 3) It is a royal pain, and a potential source of errors as things >>>>>>>>>>>> get refactored when adding new subclasses >>>>>>>>>>>> >>>>>>>>>>>> I think I have at least the seed of an idea of how to solve this, >>>>>>>>>>>> and I am hoping that one of you (who are all much smarter than I) >>>>>>>>>>>> might have the key to getting it the rest of the way. >>>>>>>>>>>> I ran into this problem again last week, and it made me think of >>>>>>>>>>>> an old language I used to use... >>>>>>>>>>>> There was a small programming language I used to use in the 90’s >>>>>>>>>>>> which had an interesting core language feature we called >>>>>>>>>>>> “handlers”. These were a lot like registering for notifications, >>>>>>>>>>>> except that writing a function (with a special “Handler” >>>>>>>>>>>> attribute: “Handler func myFuncName()") was all you needed to do >>>>>>>>>>>> to register. Writing “Handle myFuncName()” would then >>>>>>>>>>>> systematically call every function with that name and the Handler >>>>>>>>>>>> attribute. >>>>>>>>>>>> That is, instead of calling a single function, it would >>>>>>>>>>>> systematically call a series of functions (all with the same name). >>>>>>>>>>>> There was one other thing that made these handlers special. Each >>>>>>>>>>>> one had the option, when it was called, to reply that it was the >>>>>>>>>>>> one true handler, and the others didn’t need to be called. >>>>>>>>>>>> Basically, it said “I've got this!”. This even allowed it to >>>>>>>>>>>> return a result to the caller. >>>>>>>>>>>> The original intent of this feature (and why it was a core >>>>>>>>>>>> language feature) was to handle events. It would handle things >>>>>>>>>>>> like hit testing and key events fairly elegantly. It was a >>>>>>>>>>>> powerful feature, so it was quickly used for other things. It made >>>>>>>>>>>> things like plug-ins ridiculously simple. We even used it for a >>>>>>>>>>>> form of error handling. >>>>>>>>>>>> I remember helping to write a page layout program in it, and we >>>>>>>>>>>> used handlers not just for the hit testing, but for the tool >>>>>>>>>>>> palette as well. The end result was that you were able to add new >>>>>>>>>>>> shapes and new tools without modifying existing code at all. It is >>>>>>>>>>>> a feature I miss all the time... >>>>>>>>>>>> >>>>>>>>>>>> That is more power than we need here, but it provided me the >>>>>>>>>>>> inspiration for a potential solution to the factory problem. Back >>>>>>>>>>>> to swift… >>>>>>>>>>>> >>>>>>>>>>>> The idea here is to give each interested subclass a chance to say >>>>>>>>>>>> “I've got this!”. The factory init runs through each of the >>>>>>>>>>>> subclasses’ overrides until it finds one that doesn’t return nil. >>>>>>>>>>>> New subclasses can be added and they will be given a chance as >>>>>>>>>>>> well (without modifying the base class). The first subclass to >>>>>>>>>>>> successfully init wins. (only subclasses which override the >>>>>>>>>>>> factory init would be considered) >>>>>>>>>>>> >>>>>>>>>>>> class AbstractBase { >>>>>>>>>>>> public factory init?(type: InformationToSwitchOn){ >>>>>>>>>>>> //I like having an explicit call, so that the traditional >>>>>>>>>>>> (non-distributed) factory is possible as well >>>>>>>>>>>> return factory.init(type) //We could also call this >>>>>>>>>>>> “subclass.init(type)” to mirror super >>>>>>>>>>>> } >>>>>>>>>>>> } >>>>>>>>>>>> class ConcreteImplementation : AbstractBase { >>>>>>>>>>>> public factory override init?(type: InformationToSwitchOn){ >>>>>>>>>>>> guard type == compatibleWithThisType else {return nil} >>>>>>>>>>>> //If info doesn’t work for us, we return nil, and the next class >>>>>>>>>>>> gets a shot >>>>>>>>>>>> //Init concrete type here >>>>>>>>>>>> } >>>>>>>>>>>> } >>>>>>>>>>>> >>>>>>>>>>>> The main issue which still needs to be solved is that the order >>>>>>>>>>>> they get called sometimes really matters (this was solved by a >>>>>>>>>>>> well defined ordering + IDE features in the language mentioned >>>>>>>>>>>> above). For the most part, as long as subclasses are called before >>>>>>>>>>>> their superclasses (or there is a some method for cascading), it >>>>>>>>>>>> works. There are still times where you want to define a specific >>>>>>>>>>>> ordering though (e.g. a new subclass wants to get called before an >>>>>>>>>>>> existing subclasses to override some of it’s use cases). >>>>>>>>>>>> I see a few options (and I would love to hear more): >>>>>>>>>>>> - subclasses define a numeric precedence (similar to operators >>>>>>>>>>>> now). This is probably the most effective stop-gap solution, but >>>>>>>>>>>> is not elegant. >>>>>>>>>>>> - subclasses do whatever we change operator precedence to do in >>>>>>>>>>>> the future >>>>>>>>>>>> - optionally allow subclasses to name another specific subclass >>>>>>>>>>>> that they are before/after >>>>>>>>>>>> - allow subclasses to declare that they would like to be earlier >>>>>>>>>>>> or later (or that they don’t care) in the calling list. subclasses >>>>>>>>>>>> defined outside of the module where the base class was defined >>>>>>>>>>>> would be placed more extremely early/late. Exact order is >>>>>>>>>>>> undefined, but rough ordering is possible. >>>>>>>>>>>> - return (to the superclass) an array of all subclasses which >>>>>>>>>>>> successfully inited. It can then select which one it wants and >>>>>>>>>>>> return it. This seems overly inefficient to me, since you are >>>>>>>>>>>> initializing a bunch of unused objects. >>>>>>>>>>>> - <Your idea here> >>>>>>>>>>>> >>>>>>>>>>>> The end result is that you can extend factories of both classes >>>>>>>>>>>> and protocols without access to the original source code. >>>>>>>>>>>> >>>>>>>>>>>> I also don’t think that the base should always need to be >>>>>>>>>>>> abstract. Factory inits should allow returning subclasses as a way >>>>>>>>>>>> of replacing themselves with a subclass, and returning nil if they >>>>>>>>>>>> are failable, but if there is no return (or return self), it can >>>>>>>>>>>> create an instance of itself. This way, it provides a >>>>>>>>>>>> customization point where subclasses can handle special cases, but >>>>>>>>>>>> the class itself provides an obvious default (i.e. a much less >>>>>>>>>>>> messy form of class cluster). >>>>>>>>>>>> >>>>>>>>>>>> class Base { >>>>>>>>>>>> public factory init(type: InformationToSwitchOn){ >>>>>>>>>>>> if let subclass = factory.init(type){ >>>>>>>>>>>> return subclass >>>>>>>>>>>> } >>>>>>>>>>>> return self.init()//If subclasses didn’t work, initialize >>>>>>>>>>>> ourselves >>>>>>>>>>>> } >>>>>>>>>>>> } >>>>>>>>>>>> >>>>>>>>>>>> Thoughts? Too crazy to consider? >>>>>>>>>>>> >>>>>>>>>>>> Thanks, >>>>>>>>>>>> Jon >>>>>>>>>>>> >>>>>>>>>>>> On Feb 8, 2016, at 11:26 AM, Charles Srstka <cocoadev at >>>>>>>>>>>> charlessoft.com >>>>>>>>>>>> <https://lists.swift.org/mailman/listinfo/swift-evolution>> wrote: >>>>>>>>>>>> >>>>>>>>>>>> >> On Dec 17, 2015, at 3:41 PM, Riley Testut via swift-evolution >>>>>>>>>>>> >> <swift-evolution at swift.org >>>>>>>>>>>> >> <https://lists.swift.org/mailman/listinfo/swift-evolution>> >>>>>>>>>>>> >> 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 { >>>>>>>>>>>> >> >>>>>>>>>>>> >> } >>>>>>>>>>>> >> >>>>>>>>>>>> >> 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 <phausler at >>>>>>>>>>>> >>> apple.com >>>>>>>>>>>> >>> <https://lists.swift.org/mailman/listinfo/swift-evolution>> >>>>>>>>>>>> >>> 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 <brent at >>>>>>>>>>>> >>> architechies.com >>>>>>>>>>>> >>> <https://lists.swift.org/mailman/listinfo/swift-evolution>> >>>>>>>>>>>> >>> 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 >>>>>>>>>>>> >> swift-evolution at swift.org >>>>>>>>>>>> >> <https://lists.swift.org/mailman/listinfo/swift-evolution> >>>>>>>>>>>> >> https://lists.swift.org/mailman/listinfo/swift-evolution >>>>>>>>>>>> >> <https://lists.swift.org/mailman/listinfo/swift-evolution> >>>>>>>>>>>> > >>>>>>>>>>>> > Was any proposal for this ever written up? It would be really >>>>>>>>>>>> > useful to have, and it appeared to have the support of several >>>>>>>>>>>> > Apple staff members. >>>>>>>>>>>> > >>>>>>>>>>>> > Charles >>>>>>>>>>>> >>>>>>>>>> >>>>>>>>> >>>>>>>> >>>>>>> >>>>>> >>>>> >>>> >> >
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
