<html><body><div>Hi!<br><br>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.<br><br>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.<br><br>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:<br><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;">protocol StringLoadable {</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;init(string: String)</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;">}</span><br><br>And then we want a class "Car", that has a subclass "BigCar", to conform to this protocol.<br><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;">class Car: StringLoadable {</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;required convenience init(string: String) {</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if string.characters.count &lt; 10 {</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;self.init()</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else {</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let bigCar = BigCar()</span><br><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//... oops, how do i return this now?</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;}</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;">}</span><br><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;">class BigCar: Car {</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;//...</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;">}</span><br><br>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:<br><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;">class Car: StringLoadable {</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;static func loadFromString(string: String) -&gt; Car {</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if string.characters.count &lt; 10 {</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return Car()</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else {</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return BigCar()</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;}</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;">}</span><br><br>This works, but only until we try to have this as a protocol requirement:<br><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;">protocol StringLoadable {</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;static func loadFromString(string: String) -&gt; Self</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;">}</span><br><br>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.<br><br>Factory initializers would fix this problem:<br><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;">protocol StringLoadable {</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;init(string: String)</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;">}</span><br><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;">class Car: StringLoadable {</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;required <em><strong>factory</strong></em> init(string: String) {</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if string.characters.count &lt; 10 {</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return Car()</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else {</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return BigCar(string: string)</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;}</span><br><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;init() { }</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;">}</span><br><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;">class BigCar: Car {</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;required <em><strong>factory</strong></em> init(string: String) {</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return BigCar()</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;}</span><br><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;"> &nbsp;&nbsp;&nbsp;init() { }</span><br><span style="font-family: 'courier new', monospace;" data-mce-style="font-family: 'courier new', monospace;">}</span><br><br>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.<br><br>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.<br><br>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.<br><br>Here are some more ideas on factory initializers:<br><br>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.<br><br>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.</div><div><br data-mce-bogus="1"></div><div>Thank you all for reading! 😊</div><div><br data-mce-bogus="1"></div><div>C.</div></body></html>