mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
107 lines
4.0 KiB
ReStructuredText
107 lines
4.0 KiB
ReStructuredText
:orphan:
|
|
|
|
.. title:: Problems with Initializers
|
|
|
|
|
|
Problem 1: Initializers are complicated
|
|
=======================================
|
|
|
|
By formalizing Objective-C's initialization conventions, we've ended up with a
|
|
tower of complexity where users find it easier to do the wrong thing and then
|
|
follow the compiler fix-its. I [Jordan R] still feel like the individual rules
|
|
aren't so complicated:
|
|
|
|
| Designated initializers chain.
|
|
| Designated initializers are inherited if (a) there are no manual
|
|
initializers, and (b) all properties have initial values.
|
|
|
|
| Convenience initializers delegate.
|
|
| Convenience initializers are inherited if all of the superclass's
|
|
designated initializers are present.
|
|
|
|
| If you want to call an initializer on a dynamic type, it must be marked
|
|
required.
|
|
| Protocols are one way to do this, so initializers that satisfy protocol
|
|
requirements must be required.
|
|
| If your superclass has a required initializer, you must provide it
|
|
somehow.
|
|
|
|
but
|
|
|
|
"When even Andy Matuschak and Rob Rix can't understand your model, you have
|
|
a problem." - Joe Groff
|
|
|
|
|
|
Problem 2: Convenience initializers are missing use cases
|
|
=========================================================
|
|
|
|
With all our rules, we actually rule out some important use cases, like this one on NSDocument:
|
|
|
|
The ``init`` method of NSDocument is the *designated initializer,* and it is
|
|
invoked by the other initializers ``initWithType:error:`` and
|
|
``initWithContentsOfURL:ofType:error:``. If you perform initializations that
|
|
must be done when creating new documents but not when opening existing
|
|
documents, override ``initWithType:error:``. If you have any initializations
|
|
that apply only to documents that are opened, override
|
|
``initWithContentsOfURL:ofType:error:``. If you have general
|
|
initializations, override ``init``. In all three cases, be sure to invoke
|
|
the superclass implementation as the first action.
|
|
|
|
-- `Document-Based App Programming Guide for Mac`__
|
|
|
|
__ https://developer.apple.com/library/mac/documentation/DataManagement/Conceptual/DocBasedAppProgrammingGuideForOSX/ManagingLifecycle/ManagingLifecycle.html#//apple_ref/doc/uid/TP40011179-CH4-SW11
|
|
|
|
Because we don't allow overriding convenience initializers with other
|
|
convenience initializers, there's nowhere to perform post-customization of
|
|
NSDocuments for each particular case.
|
|
|
|
|
|
Problem 3: Factory Initializers
|
|
===============================
|
|
|
|
Finally, we try to standardize on initializers for object creation in Swift,
|
|
even going as far as to import Objective-C factory methods as initializers...but
|
|
there are some patterns that cannot be written in Swift, such as this one::
|
|
|
|
class AnyGenerator<Element> : GeneratorType {
|
|
init<
|
|
WrappedGenerator: GeneratorType
|
|
where
|
|
WrappedGenerator.Element == Element
|
|
>(wrapped: WrappedGenerator) -> AnyGenerator {
|
|
return AnyGeneratorImpl(wrapped)
|
|
}
|
|
// other generator stuff
|
|
}
|
|
|
|
class AnyGeneratorImpl<WrappedGenerator: GeneratorType> :
|
|
AnyGenerator<WrappedGenerator.Element> {
|
|
var wrapped: WrappedGenerator
|
|
init(wrapped: WrappedGenerator) {
|
|
self.wrapped = wrapped
|
|
}
|
|
// other generator stuff
|
|
}
|
|
|
|
We ended up making ``AnyGenerator`` a struct that wraps ``AnyGeneratorImpl`` to
|
|
get around this, but it's not a nice solution.
|
|
|
|
|
|
Solutions?
|
|
==========
|
|
|
|
We've had a number of ideas for improving the state of the world, including
|
|
|
|
- Allow designated initializers to delegate to other designated initializers
|
|
(using static dispatch). This makes convenience initializers a niche feature.
|
|
|
|
- Add the concept of factory initializers, which don't promise to return
|
|
``Self``. These are either never inherited or must always be overridden in a
|
|
subclass.
|
|
|
|
- Allow convenience initializers to chain to superclass convenience
|
|
initializers. This isn't strictly safe, but it permits the NSDocument idiom.
|
|
|
|
None of these solve all the initializer problems listed above on their own, and
|
|
we'd want to be careful not to *increase* complexity in this space.
|