[swift-evolution] [Proposal] Factory Initializers

Jonathan Hull jhull at gbis.com
Tue Mar 21 16:09:16 CDT 2017


There are several reasons.  It is a very common pattern in ObjC/Cocoa.  For example, they allow class clusters (and the protocol equivalent).

One of the Apple foundation people replied earlier in this thread that it would allow them to remove several hacks from the foundation overlays, and improve safety.

One of the ideas I am most excited about is the ability for a protocol to provide default conformances.  For example, I have an Expression protocol to represent mathematical expressions, and I have a few basic conforming structs representing constants, variables, and some basic operations.  With a factory method, I can say ‘Expression(2)’ or ‘Expression(“VarName”)’ and have it create the correct conformance.  My conforming structs can even be private, if I want this to be the only way they are created.

If I have expensive-to-create immutable objects where I am creating equivalent values all the time, I can store commonly created values in a cache and return the cached versions (instead of creating an instance).  I believe cocoa used to do this with NSNumbers before tagged pointers became a thing.

Or, I could return something which is lazily created.

Longer term (once reflection has improved), I have a proposal to allow extensible factory methods. We talked about it during the original discussion, but the gist is that there would be way to get a list of all types conforming to a protocol (or all subclasses of a class) from the compiler, and then you could use static methods to query those types until you found one which has the properties you are looking for, and then instantiate and return it.  The end result is that you have a factory initializer where new conformances (even from plug-ins) can participate and be returned when appropriate.  This proposal is a necessary first step to that.

As a concrete use-case of that extension, I have been experimenting for years with auto-creating UI to edit structured data (e.g. JSON or Plists) or objects.  This is fairly easy in ObjC, but it is only possible in Swift in a very limited way at the moment.  With the above extension and key paths, I should be able to recreate my ObjC interfaces in a nicer/swiftier way.

Those are just a few of the uses.

Thanks,
Jon

> On Mar 21, 2017, at 8:49 AM, David Rönnqvist via swift-evolution <swift-evolution at swift.org> wrote:
> 
> Forgive me if that has already been discussed in the email threads prior to the proposal, but what I’m missing from this proposal is a discussion of the problems factory initializers solve (other than the examples at the end) and an explanation of why factory initializers are the right solution to that/those problems in Swift.
> 
> I acknowledge that it’s a common pattern in many languages, but don’t find it a very strong argument as to why it should be built into the language. 
>  
> Regards,
> David
> 
> 
>> On 17 Mar 2017, at 17:26, Riley Testut via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>> 
>> Hi again everyone!
>> 
>> Now that Swift 4 Stage 2 proposals are being considered, I thought it might be time to revisit this proposal and see if it might align with the goals set forth for Swift 4.
>> 
>> As a quick tl;dr, this proposal describes a new "factory initializer" that would allow you to return a value from an initializer. This would have several benefits, as mentioned in the proposal itself as well as throughout this mailing list. For convenience, here's a link to the proposal on GitHub: 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>
>> 
>> Would love to hear any more comments on this proposal, and if we feel this is appropriate for considering for Swift 4 I'll happily re-open the pull request!
>> 
>> Riley Testut
>> 
>> On Nov 19, 2016, at 7:45 AM, arkadi daniyelian <arkdan at icloud.com <mailto:arkdan at icloud.com>> wrote:
>> 
>>> i would appreciate this feature.
>>> 
>>> For unexperienced developers, its often hard to recognize *when* factory is a good fit to do the job, and how exactly approach the implementation. I imagine having this feature built into the language may help to choose and implement factory when its the right thing to do.
>>> 
>>>> On Nov 18, 2016, at 12:23 AM, Charles Srstka via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>>> 
>>>> Is there any chance of reviving this? It seems to me that since this would require Swift initializers to be implemented internally in such a way that they can return a value (as Objective-C init methods do), it may affect ABI stability and thus may be germane to the current stage of Swift 4 development.
>>>> 
>>>> Charles
>>>> 
>>>>> On Dec 17, 2015, at 3:41 PM, Riley Testut via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> 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 <mailto:phausler at apple.com>> 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 <mailto:brent at architechies.com>> 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 <mailto:swift-evolution at swift.org>
>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
>>>> 
>>>> _______________________________________________
>>>> swift-evolution mailing list
>>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170321/f91244bf/attachment.html>


More information about the swift-evolution mailing list