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