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.
 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]> 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

Reply via email to