[swift-evolution] Factory initializers
Andrew Bennett
cacoyi at gmail.com
Tue Jan 19 15:50:13 CST 2016
Hi Claus,
It looks like you've put a lot of thought and consideration into how this
could fit into Swift :)
There was early proposals for class clusters that turned into a discussion
on factory initialisers. You'll probably find a lot of shared goals and
ideas here:
http://comments.gmane.org/gmane.comp.lang.swift.evolution/17
It would be great once you've read through that thread to contribute your
ideas to it!
Andrew
On Wed, Jan 20, 2016 at 4:47 AM, Claus Ruete via swift-evolution <
swift-evolution at swift.org> wrote:
> Hi!
>
> I hope this is the right mailing list for this: I want to make a proposal
> for the swift language. This is not in the commonly rejected changes and i
> also haven't found it anywhere else, so hopefully I am doing this right.
>
> What I would like to see in swift is a better way of implementing "factory
> methods" that return an instance of a class, but unlike normal
> initializers, may return an instance of a subclass instead of just the
> class itself.
>
> Let me explain one important use case why i think this would be a good
> idea. Imagine we define a protocol requiring an initializer like this:
>
> protocol StringLoadable {
> init(string: String)
> }
>
> And then we want a class "Car", that has a subclass "BigCar", to conform
> to this protocol.
>
> class Car: StringLoadable {
> required convenience init(string: String) {
> if string.characters.count < 10 {
> self.init()
> }
> else {
> let bigCar = BigCar()
>
> //... oops, how do i return this now?
> }
> }
> }
>
> class BigCar: Car {
> //...
> }
>
> So the Car should be a BigCar in case the string contains 10 characters or
> more. Now the only way i could see this possibly work is to use a static
> fun instead of an initializer:
>
> class Car: StringLoadable {
> static func loadFromString(string: String) -> Car {
> if string.characters.count < 10 {
> return Car()
> }
> else {
> return BigCar()
> }
> }
> }
>
> This works, but only until we try to have this as a protocol requirement:
>
> protocol StringLoadable {
> static func loadFromString(string: String) -> Self
> }
>
> While i already dislike that the whole protocol (and thus, the API) have
> to change just because of an implementation detail in one class, the even
> bigger problem is that for non-final classes, it is impossible to implement
> this required static function: Having it return "Car" does not satisfy the
> protocol, because we end up in a situation where BigCar.loadFromString(_:)
> returns a Car instead of a BigCar.
>
> Factory initializers would fix this problem:
>
> protocol StringLoadable {
> init(string: String)
> }
>
> class Car: StringLoadable {
> required *factory* init(string: String) {
> if string.characters.count < 10 {
> return Car()
> }
> else {
> return BigCar(string: string)
> }
> }
>
> init() { }
> }
>
> class BigCar: Car {
> required *factory* init(string: String) {
> return BigCar()
> }
>
> init() { }
> }
>
> In this case, the factory init is marked as "required" for protocol
> conformance, but in other use cases it doesn't have to be required. A
> factory init would act mostly like a convenience init, with the exception
> of being able to initialize a subclass or load an object from somewhere
> else, for example a cache or something like that.
>
> A factory initializer would never allocate any memory itself, that work
> happens in the actual designated initializer. Also, like a convenience
> initializer, a class cannot only have a factory initializer, but needs at
> least one designated initializer. Because of this, factory initializers
> would not cause any problems in terms of being able to access uninitialized
> properties or something like that.
>
> I hope you agree that factory initializers would be a good addition to
> swift. As shown in the example, they allow things to be implemented that
> weren't before, and they don't cause any problems with type safety or any
> other Swift concepts.
>
> Here are some more ideas on factory initializers:
>
> We could have factory initializers in protocol extensions: In some cases,
> this would allow to completely hide the actual implementations of that
> protocol – by being able to "construct" a protocol.
>
> In terms of the syntax, instead of using a "return" pattern, the "assign
> to self" pattern, as known from enum initializers, could be used, but i
> think using self in a factory initializer could cause confusion (The
> compiler would have to prevent "self" from being used before it was
> assigned a value), so i prefer the "return" pattern with no access to
> "self" at all.
>
> Thank you all for reading! 😊
>
> C.
>
> _______________________________________________
> 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/20160120/359b0cf1/attachment.html>
More information about the swift-evolution
mailing list