On Tue, 27 Jun 2017 at 00:00 Karl Wagner via swift-evolution < swift-evolution@swift.org> wrote:
On 26. Jun 2017, at 13:44, Karl Wagner <razielim@gmail.com> wrote:
On 25. Jun 2017, at 22:13, Robert Bennett <rltbennett@icloud.com> wrote:
For a concrete type, a partial initializer is a function that:
Can set `let` instance variables
May not refer to `self` in an rvalue
Must set the same subset of instance variables regardless of the code path
taken
For a protocol, a partial initializer is simply a function that sets *any*
subset of the instance variables. A protocol could provide a default
implementation of one. In order for this `let` proposal to work, though, if
a `let` variable is set in the protocol extension’s implementation of a
(full) initializer, the protocol would need to provide at least one partial
initializer that it does not provide an implementation for, so that a
conforming type can fill in the gaps for all of the instance variables it
defines that the protocol doesn’t require/know about. That way the compiler
can have faith that a conforming type will be able to fully initialize
itself with the default implementation of the required full initializer.
I’ll say again: I think you’re approaching this from the wrong angle. You
want stronger guarantees about mutability of properties, but the answer is
not to make protocols be more restrictive about how conformers are written.
What you are really asking for is the guarantee that some type which
conforms to SomeProtocol has value-semantics. Once you have that guarantee,
you know that you have a unique instance whose properties will only mutate
if they are stored in a “var” property and you yourself mutate it.
For example, an Array’s “count” property is technically a computed
property, but in a “let”-declared Array you can treat it as a “let”
constant because Arrays have value semantics. Your guarantees about
properties only being set in the initialiser would automatically be
fulfilled without the need of any additional alternate initialisation
patterns.
- Karl
Just to expand on this a little bit, as I see it there are two parts to
your problem. First, you were asking for some kind of
partial-initialisation. Second, you (or somebody) mentioned that there
might be optimisation benefits.
Here’s a kind of partial initialisation you can use right now:
public protocol SomeProtocol {
var neverReallyMutatesAfterInit: String { get }
}
public extension SomeProtocol {
static func withProtocolDefaults() -> SomeProtocol? {
return (Self.self as? PartiallyInitializableSomeProtocol.Type).map
{ $0.withProtocolDefaults() }
}
}
internal protocol PartiallyInitializableSomeProtocol: SomeProtocol {
/// Creates an object with type-specific defaults.
init()
/// Allows customisation by the protocol after init.
var neverReallyMutatesAfterInit: String { get set }
}
internal extension PartiallyInitializableSomeProtocol {
static func withProtocolDefaults() -> SomeProtocol {
var newValue = Self()
newValue.neverReallyMutatesAfterInit = "ProtocolDefault"
return newValue
}
}
public struct SomeConformer: PartiallyInitializableSomeProtocol {
public internal(set) var neverReallyMutatesAfterInit = "TypeDefault"
internal init() {}
}
(SomeConformer.self as
SomeProtocol.Type).withProtocolDefaults()?.neverReallyMutatesAfterInit //
"ProtocolDefault"
With this example, the only way users of your library can obtain an
instance is via the protocol function, which knows that it can construct a
default instance and specialise the values.
As far as optimisation goes - I have to correct myself, because even in a
protocol existential whose underlying type is known to have value
semantics, computed properties themselves might not. For all the compiler
knows, they could be reading/writing from global state. So the compiler
can’t really eliminate repeat accesses unless it knows the underlying
implementation (or we give it more information about how the content
mutates). People have asked about marking stored/computed properties in
protocols before, and I’ve always been against it. Protocols should contain
abstract, semantic information with as little implementation-constraining
stuff as possible whilst retaining the contract. That’s what makes them so
powerful.
- Karl
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution