Nice! I must admit, my first reaction to this proposal was “uhhh, why complicate initializers even more?”. But then I hit these two roadblocks:
1. I wanted to add an initializer on `NSTimer` extension that returns the (toll-free-bridged) value from CFRunLoopTimerCreateWithHandler. Sadly, this is impossible, and so I have to write NSTimer.new(…) <https://github.com/radex/SwiftyTimer/blob/3b4f233989dd60dc2dd728659e5bcf750a8c9f2f/Sources/SwiftyTimer.swift#L65> :( 2. I wanted to add a custom initializer to a class inheriting from UIButton. But I can’t, because the initializer for UIButton is `convenience init(type buttonType: UIButtonType)` :( A `factory init` allowing me to use both the initializer syntax and return an object from some other initializer would solve both problems. The "Initializing Storyboard-backed View Controller” use case is also compelling to me. +1. — Radek > On 09 Apr 2016, at 21:17, Riley Testut via swift-evolution > <[email protected]> wrote: > > 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 > <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] >> <mailto:[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
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
