|
| 1 | +:orphan: |
| 2 | + |
| 3 | +.. title:: Problems with Initializers |
| 4 | + |
| 5 | + |
| 6 | +Problem 1: Initializers are complicated |
| 7 | +======================================= |
| 8 | + |
| 9 | +By formalizing Objective-C's initialization conventions, we've ended up with a |
| 10 | +tower of complexity where users find it easier to do the wrong thing and then |
| 11 | +follow the compiler fix-its. I [Jordan R] still feel like the individual rules |
| 12 | +aren't so complicated: |
| 13 | + |
| 14 | + | Designated initializers chain. |
| 15 | + | Designated initializers are inherited if (a) there are no manual |
| 16 | + initializers, and (b) all properties have initial values. |
| 17 | +
|
| 18 | + | Convenience initializers delegate. |
| 19 | + | Convenience initializers are inherited if all of the superclass's |
| 20 | + designated initializers are present. |
| 21 | +
|
| 22 | + | If you want to call an initializer on a dynamic type, it must be marked |
| 23 | + required. |
| 24 | + | Protocols are one way to do this, so initializers that satisfy protocol |
| 25 | + requirements must be required. |
| 26 | + | If your superclass has a required initializer, you must provide it |
| 27 | + somehow. |
| 28 | +
|
| 29 | +but |
| 30 | + |
| 31 | + "When even Andy Matuschak and Rob Rix can't understand your model, you have |
| 32 | + a problem." - Joe Groff |
| 33 | + |
| 34 | + |
| 35 | +Problem 2: Convenience initializers are missing use cases |
| 36 | +========================================================= |
| 37 | + |
| 38 | +With all our rules, we actually rule out some important use cases, like this one on NSDocument: |
| 39 | + |
| 40 | + The ``init`` method of NSDocument is the *designated initializer,* and it is |
| 41 | + invoked by the other initializers ``initWithType:error:`` and |
| 42 | + ``initWithContentsOfURL:ofType:error:``. If you perform initializations that |
| 43 | + must be done when creating new documents but not when opening existing |
| 44 | + documents, override ``initWithType:error:``. If you have any initializations |
| 45 | + that apply only to documents that are opened, override |
| 46 | + ``initWithContentsOfURL:ofType:error:``. If you have general |
| 47 | + initializations, override ``init``. In all three cases, be sure to invoke |
| 48 | + the superclass implementation as the first action. |
| 49 | + |
| 50 | + -- `Document-Based App Programming Guide for Mac`__ |
| 51 | + |
| 52 | +__ https://developer.apple.com/library/mac/documentation/DataManagement/Conceptual/DocBasedAppProgrammingGuideForOSX/ManagingLifecycle/ManagingLifecycle.html#//apple_ref/doc/uid/TP40011179-CH4-SW11 |
| 53 | + |
| 54 | +Because we don't allow overriding convenience initializers with other |
| 55 | +convenience initializers, there's nowhere to perform post-customization of |
| 56 | +NSDocuments for each particular case. |
| 57 | + |
| 58 | + |
| 59 | +Problem 3: Factory Initializers |
| 60 | +=============================== |
| 61 | + |
| 62 | +Finally, we try to standardize on initializers for object creation in Swift, |
| 63 | +even going as far as to import Objective-C factory methods as initializers…but |
| 64 | +there are some patterns that cannot be written in Swift, such as this one:: |
| 65 | + |
| 66 | + class AnyGenerator<Element> : GeneratorType { |
| 67 | + init< |
| 68 | + WrappedGenerator: GeneratorType |
| 69 | + where |
| 70 | + WrappedGenerator.Element == Element |
| 71 | + >(wrapped: WrappedGenerator) -> AnyGenerator { |
| 72 | + return AnyGeneratorImpl(wrapped) |
| 73 | + } |
| 74 | + // other generator stuff |
| 75 | + } |
| 76 | + |
| 77 | + class AnyGeneratorImpl<WrappedGenerator: GeneratorType> : |
| 78 | + AnyGenerator<WrappedGenerator.Element> { |
| 79 | + var wrapped: WrappedGenerator |
| 80 | + init(wrapped: WrappedGenerator) { |
| 81 | + self.wrapped = wrapped |
| 82 | + } |
| 83 | + // other generator stuff |
| 84 | + } |
| 85 | + |
| 86 | +We ended up making ``AnyGenerator`` a struct that wraps ``AnyGeneratorImpl`` to |
| 87 | +get around this, but it's not a nice solution. |
| 88 | + |
| 89 | + |
| 90 | +Solutions? |
| 91 | +========== |
| 92 | + |
| 93 | +We've had a number of ideas for improving the state of the world, including |
| 94 | + |
| 95 | +- Allow designated initializers to delegate to other designated initializers |
| 96 | + (using static dispatch). This makes convenience initializers a niche feature. |
| 97 | + |
| 98 | +- Add the concept of factory initializers, which don't promise to return |
| 99 | + ``Self``. These are either never inherited or must always be overridden in a |
| 100 | + subclass. |
| 101 | + |
| 102 | +- Allow convenience initializers to chain to superclass convenience |
| 103 | + initializers. This isn't strictly safe, but it permits the NSDocument idiom. |
| 104 | + |
| 105 | +None of these solve all the initializer problems listed above on their own, and |
| 106 | +we'd want to be careful not to *increase* complexity in this space. |
0 commit comments