On Monday, 11 January 2016, Douglas Gregor via swift-evolution < swift-evolution@swift.org> wrote:
On Jan 10, 2016, at 6:43 PM, Wallacy via swift-evolution < > swift-evolution@swift.org > <javascript:_e(%7B%7D,'cvml','swift-evolution@swift.org');>> wrote:
TL;DR
Thinking about some problems presented here this mailing list. I believe
that by following the same concepts behind the default protocol
implementations, allowing the same mechanism to provide default properties
can be a remarkable gain for language.
Rationale:
It has been proposed here also on this list, a need to produce abstract
classes, one of the reasons that need, is because is not possible to
declare properties in the same way as we declare default implementation on
protocols.
I also believe that this can help in the concept of multiple inheritance,
and serve as an aid to the default implementation on protocols, and
"complete" the Protocol-Oriented Programming concept.
For example:
protocol Named {
var name: String { get }
}
protocol Aged {
var age: Int { get }
}
struct Person: Named, Aged {
var name: String
var age: Int
}
extension Aged where Self: Named {
func wishHappyBirthday() { // regular default implementation
print("Happy birthday \(self.name) - you're \(self.age)!")
}
var birthdayVideo: AVPlayerItem? // nil is a default value
}
...
func playBirthdayMediaFrom(person: Person){
var avPlayer = AVPlayer(playerItem: person.birthdayVideo)
// etc...
}
One of thousands of using this feature is to prevent us to create
variables that are not actually part of the data model we are shaping.
birthdayVideo in this case would be any variable that is not part of our
model, but need to be associated with the object (or structure) in some
context of our application. (And not be used anywhere else in the APP or
another API).
Other examples maybe a counter helper, weak reference to something, etc.
There is a infinite examples when we need to declare some variable just to
make the "api" happy like add a observer, holding some value, and use this
again to removeobserver in dealloc.
I believe that the same rules and the same mechanisms involving default
implementation functions, should govern this default property
implementation, and any discussion about it on the problems on protocols
rules should be made separate this thread.
Default implementations of functions don’t require per-instance state,
while adding a stored property via a protocol extension does. Let’s step
back to a simpler problem: stored properties in (non-protocol) extensions.
In the existing language, one can only introduce stored properties in the
primary definition of the type. That’s because, when we create an instance
of that type, we need to know how much storage to allocate for that
instance. So, right now, we don’t even allow, e.g.,
struct MyStruct { }
extension MyStruct { var storage: Int = 0 } // error: extensions may not
contain stored properties
class MyClass { }
extension MyClass { var storage: Int = 0 } // error: extensions may not
contain stored properties
because, in the worst case, we don’t know about the storage required for
the “storage” property until after we’ve allocated some instances of
MyStruct or MyClass, and we can’t simply go back and resize those instances
when we learn about the “storage” property. The “worst case” here could
come about with shared libraries: put the MyStruct/MyClass primary
definitions into an app, then put the extensions into a separate shared
library. The app creates some MyStruct and MyClass instances, then loads
the shared library, and now we have a problem: those instances have no
storage for “storage.”
We could relax the requirement to allow extensions in the same module as
the primary definition of that type to introduce stored properties, because
they’re compiled along with the primary type definition anyway. This
doesn’t solve out-of-module extensions, of course.
We could embed a pointer into each instance that points off to the stored
properties for that instance. The pointer would refer to some
lazily-allocated memory on the heap with that extra storage. However, this
would either bloat every data structure by a pointer (including “Int”!) or
have to be opt-in, neither of which are great. I don’t think there is any
reasonable implementation for out-of-module stored properties in extensions
of value types (struct/enum).
For classes, where we have object identity, we could have a side table
containing the stored properties (keyed on the object’s address). This is
how Objective-C’s associated objects work, and it’s a reasonable module for
out-of-module stored properties in extensions of classes.
Getting back to stored properties in protocol extensions, the general
feature isn’t implementable without having some mechanism for out-of-module
stored properties in extensions of structs and enums, so you can limit it
in a few ways:
* Only allow them on class-bound protocols, where there is a reasonable
implementation model
* Allow them as default implementations within a protocol (not an
extension of a protocol!); a type can conform to that protocol either by
providing its own implementation of that property or somewhere where it is
reasonable for the default implementation to inject a stored property into
that context (e.g., on the primary type, within the same module as the
primary type, or on a class).
Either handles the example brought up in the discussion of abstract base
classes.
- Doug