On 2016-07-09 04:39:01 +0000, Jordan Rose via swift-evolution said:
I wanted to share a concrete use case that Daniel Dunbar relayed to me.
He was working on a closed class hierarchy like the ones discussed
here, where all of the subclasses are within a single module, but they
are all public. The class also has a required initializer for dynamic
construction, so that they could write something like this:
internal struct ModelContext { /*…*/ }
public class ModelBase {
internal required init(context: ModelContext) { /*…*/ }
// …
}
public class SimpleModel: ModelBase {
internal required init(context: ModelContext) { /*…*/ }
}
public class MoreComplicatedModel: ModelBase { /*…*/ }
// (within some other type)
public func instantiateModelObject<Model: ModelBase>(_ type: Model) -> Model {
return type.init(context: self.context)
}
That is, a public entry point calls a required initializer with an
internal argument type. This is the only way to instantiate Model
objects, and the internal context type doesn’t leak out into the public
API.
Of course, Swift doesn’t allow this. If someone outside of the module
subclasses ModelBase, there’s no way for them to provide the
dynamically-dispatched 'init(context:)’, because they don’t have access
to the internal ModelContext. The author of the library has to make the
required initializers public, and either set the ModelContext
separately or make it public as well. Even though no one outside the
module should be using these APIs.
Can you remind us why does Swift need required initializers to have the
same access as the containing class?
Having only package-internal constructors in the public base class is
the usual pattern for exporting a sealed class hierarchy in some other
languages, like Java.
--
Károly
@lorentey
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution