Properties on Default Protocol Implementations


(Wallacy) #1

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.


(Douglas Gregor) #2

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

···

On Jan 10, 2016, at 6:43 PM, Wallacy via swift-evolution <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 <http://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.


(Chris Lattner) #3

Hi Doug,

Have you considered this similar-but-different approach?

- Allow extensions on classes (only) within the same module/resilience domain as the class to add stored properties. This would keep them inline in the instance.
- Allow protocols to have stored property declarations, introducing a new “protocol with storage” (PwS) concept.
- Classes can directly conform to a PwS in its definition, or within an extension inside the same module/resilience domain.

Just this would give many of the benefits of a full mix-in programming model. People could define these protocols, and their local implementation of the type can benefit from them. It doesn’t support retroactive mixin’ing, but that is probably a good thing. I’m assuming that we don’t want to allow adding state to structs within a resilience domain, just because I don’t think that is actually a good thing to add to the programming model (other reasonable people will surely disagree).

This base model could then be extended:
- Structs could conform to a PwS in their definition, but not an extension. We could optionally require the struct to redeclare the properties to improve readability of the struct, but it wouldn’t be required from an implementation perspective.
- Classes could conform to a PwS across resilience boundaries, but wouldn’t get the state: they’d have to implement the storage requirement with a computed property.
- We could introduce an “associated objects” property behavior that makes providing the computed property very straight-forward, using the out of band implementation approach of ObjC.

The advantages of this approach I see are:

1) implementable, always a bonus.
2) keeps predictable performance. You don’t get out “associated objects” overhead unexpectedly. All state is always stored inline.
3) retroactive mixins are possible, but explicit.

The primary downside of this approach is that it introduces yet another weird protocol variant with limitations and behaviors, making the model more complicated.

-Chris

···

On Jan 10, 2016, at 8:34 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

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.

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.


(Wallacy) #4

To be honest, I did not expect was to find some kind of consensus with
respect to structs. The technical challenge appears to be greater than the
benefit.

And about class, I imagine that today would only be possible to implement
using objc protocols, right? Using the associated objects mechanism.

Keeping limited to objc protocols is a feature that might be worth?

"
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)
"

The problem with that is will make the protocol to much limited or not?
Maybe not worth the trouble.

···

Em seg, 11 de jan de 2016 às 02:34, Douglas Gregor <dgregor@apple.com> escreveu:

On Jan 10, 2016, at 6:43 PM, Wallacy via swift-evolution < > 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


(Howard Lovatt) #5

I suspect it is easier both for the compiler and the programmer to allow
abstract classes and abstract functions within abstract classes than
allowing extensions and by extension (pun intended) protocols to have
stored properties. There is precedence for this approach, in Scala and
Java you can have their equivalents of calculated properties in protocols
but not stored properties. Both Scala and Java have abstract classes and
this seems to work well.

···

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

--
  -- Howard.


(Douglas Gregor) #6

I suspect it is easier both for the compiler and the programmer to allow abstract classes and abstract functions within abstract classes than allowing extensions and by extension (pun intended) protocols to have stored properties.

Developers independently want the ability to add stored properties in extensions (at least for classes). The delta from that to stored properties as default implementations in protocols isn’t that large, and if it’s a better modeling of the problems abstract classes are meant to solve, that’s the right thing to do. Other than stored properties, what important problems do abstract classes solve that protocols don’t?

There is precedence for this approach, in Scala and Java you can have their equivalents of calculated properties in protocols but not stored properties. Both Scala and Java have abstract classes and this seems to work well.

Numerous languages have abstract classes; the question is whether they are the right answer in Swift.

  - Doug

···

On Jan 10, 2016, at 9:03 PM, Howard Lovatt <howard.lovatt@gmail.com> wrote:

On Monday, 11 January 2016, Douglas Gregor via swift-evolution <swift-evolution@swift.org <mailto: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 <http://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

--
  -- Howard.


(Douglas Gregor) #7

To be honest, I did not expect was to find some kind of consensus with respect to structs. The technical challenge appears to be greater than the benefit.

And about class, I imagine that today would only be possible to implement using objc protocols, right? Using the associated objects mechanism.

Keeping limited to objc protocols is a feature that might be worth?

IMO, If we don’t do it portably for all classes and class-bound protocols, it’s not worth it. We don’t really want to introduce new @objc-only features.

"
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)
"

The problem with that is will make the protocol to much limited or not? Maybe not worth the trouble.

Possibly not worth the trouble. If nothing else, it’s very hard to explain the limitations without deep-diving into the implementation details, which is an indicator that it’s “too complicated."

  - Doug

···

On Jan 11, 2016, at 6:08 AM, Wallacy <wallacyf@gmail.com> wrote:

Em seg, 11 de jan de 2016 às 02:34, Douglas Gregor <dgregor@apple.com <mailto:dgregor@apple.com>> escreveu:

On Jan 10, 2016, at 6:43 PM, Wallacy via swift-evolution <swift-evolution@swift.org <mailto: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 <http://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


(Douglas Gregor) #8

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.

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.

Hi Doug,

Have you considered this similar-but-different approach?

Not this particular shade, but I understand your motivation.

- Allow extensions on classes (only) within the same module/resilience domain as the class to add stored properties. This would keep them inline in the instance.
- Allow protocols to have stored property declarations, introducing a new “protocol with storage” (PwS) concept.
- Classes can directly conform to a PwS in its definition, or within an extension inside the same module/resilience domain.

Just this would give many of the benefits of a full mix-in programming model. People could define these protocols, and their local implementation of the type can benefit from them. It doesn’t support retroactive mixin’ing, but that is probably a good thing. I’m assuming that we don’t want to allow adding state to structs within a resilience domain, just because I don’t think that is actually a good thing to add to the programming model (other reasonable people will surely disagree).

This base model could then be extended:
- Structs could conform to a PwS in their definition, but not an extension. We could optionally require the struct to redeclare the properties to improve readability of the struct, but it wouldn’t be required from an implementation perspective.
- Classes could conform to a PwS across resilience boundaries, but wouldn’t get the state: they’d have to implement the storage requirement with a computed property.
- We could introduce an “associated objects” property behavior that makes providing the computed property very straight-forward, using the out of band implementation approach of ObjC.

The advantages of this approach I see are:

1) implementable, always a bonus.

This isn’t a different from my proposal in that regard :wink:

2) keeps predictable performance. You don’t get out “associated objects” overhead unexpectedly. All state is always stored inline.
3) retroactive mixins are possible, but explicit.

… this is the real benefit, and I agree. The overhead of associated objects should require one to explicitly opt-in.

The primary downside of this approach is that it introduces yet another weird protocol variant with limitations and behaviors, making the model more complicated.

I think these semantics are reasonable, and the limitation is the same as what I proposed: it’s hard to describe why the limitations are what they are without a deep-dive into the implementation model.

  - Doug

···

On Jan 11, 2016, at 10:27 AM, Chris Lattner <clattner@apple.com> wrote:
On Jan 10, 2016, at 8:34 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:


(Yang Wu) #9

I prefer Ruby's module mixing over Java's long inheritance path
(AbstractBase <|= Abstract <|= DefaultBase <|= ...).

In objc, non-fragile instance variables already allow changing base
class without re-compiling sub class, it should not be that hard to
support this feature. And I agree it is better not allowed for struct
in Swift because of semantic of value type.

···

On Mon, Jan 11, 2016 at 1:37 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 10, 2016, at 9:03 PM, Howard Lovatt <howard.lovatt@gmail.com> wrote:

I suspect it is easier both for the compiler and the programmer to allow
abstract classes and abstract functions within abstract classes than
allowing extensions and by extension (pun intended) protocols to have stored
properties.

Developers independently want the ability to add stored properties in
extensions (at least for classes). The delta from that to stored properties
as default implementations in protocols isn’t that large, and if it’s a
better modeling of the problems abstract classes are meant to solve, that’s
the right thing to do. Other than stored properties, what important problems
do abstract classes solve that protocols don’t?

There is precedence for this approach, in Scala and Java you can have their
equivalents of calculated properties in protocols but not stored properties.
Both Scala and Java have abstract classes and this seems to work well.

Numerous languages have abstract classes; the question is whether they are
the right answer in Swift.

- Doug

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> 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

--
  -- Howard.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
Best Regards!

Yang Wu
--------------------------------------------------------
Location: Pudong, Shanghai, China.
EMail : pinxue@gmail.com
Website: http://www.time2change.mobi http://rockplayer.com
Twitter/Weibo : @pinxue


(Wallacy) #10

FWIW:

I quick look of my code base (in ObjC), i found 39 code points with I use
ObjC associated objects, one of them is a crazy database manager (for
postgres) with automatic look for the database, search the tables, search
for the program to find classes with the same name, and automatic add a
observer for all rows properties that match (surprisingly works).

Others codes are more simpler, but my point with this proposal, despite all
technical issues, is avoid some "to much creative" solutions to model the
code, one in particular I am looking now (in swift), has 8 core data
properties, and 8 transient and irrelevante properties just to maintain the
everything sane (like avplayer Periodic Time Observer), and all 8 has
default implementation using extensions, will be good declare some of the
storage properties in a protocol and make each "behavior" (like monitoring
the avplayer) a protocol to be reused.

And think about the PwS noted by Chris, yes, maybe can be confusing add
another "kind" of protocols, but like the Self requirement, generally, if
well implemented, its just a matter of time (not so much) to people
understand and drive a good protocol-oriented-programing code.

···

Em seg, 11 de jan de 2016 às 16:35, Douglas Gregor <dgregor@apple.com> escreveu:

> On Jan 11, 2016, at 10:27 AM, Chris Lattner <clattner@apple.com> wrote:
>
> On Jan 10, 2016, at 8:34 PM, Douglas Gregor via swift-evolution < > swift-evolution@swift.org> wrote:
>> 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.
>>
>> 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.
>
> Hi Doug,
>
> Have you considered this similar-but-different approach?

Not this particular shade, but I understand your motivation.

>
> - Allow extensions on classes (only) within the same module/resilience
domain as the class to add stored properties. This would keep them inline
in the instance.
> - Allow protocols to have stored property declarations, introducing a
new “protocol with storage” (PwS) concept.
> - Classes can directly conform to a PwS in its definition, or within an
extension inside the same module/resilience domain.
>
> Just this would give many of the benefits of a full mix-in programming
model. People could define these protocols, and their local implementation
of the type can benefit from them. It doesn’t support retroactive
mixin’ing, but that is probably a good thing. I’m assuming that we don’t
want to allow adding state to structs within a resilience domain, just
because I don’t think that is actually a good thing to add to the
programming model (other reasonable people will surely disagree).
>
> This base model could then be extended:
> - Structs could conform to a PwS in their definition, but not an
extension. We could optionally require the struct to redeclare the
properties to improve readability of the struct, but it wouldn’t be
required from an implementation perspective.
> - Classes could conform to a PwS across resilience boundaries, but
wouldn’t get the state: they’d have to implement the storage requirement
with a computed property.
> - We could introduce an “associated objects” property behavior that
makes providing the computed property very straight-forward, using the out
of band implementation approach of ObjC.
>
> The advantages of this approach I see are:
>
> 1) implementable, always a bonus.

This isn’t a different from my proposal in that regard :wink:

> 2) keeps predictable performance. You don’t get out “associated
objects” overhead unexpectedly. All state is always stored inline.
> 3) retroactive mixins are possible, but explicit.

… this is the real benefit, and I agree. The overhead of associated
objects should require one to explicitly opt-in.

> The primary downside of this approach is that it introduces yet another
weird protocol variant with limitations and behaviors, making the model
more complicated.

I think these semantics are reasonable, and the limitation is the same as
what I proposed: it’s hard to describe why the limitations are what they
are without a deep-dive into the implementation model.

        - Doug


(Chris Lattner) #11

Up for debate. An automatic approach brings hesitation to me, because I don’t want it to be the difference between:

protocol P {
  var x : Int { get }
}

and:

protocol P {
  var x : Int
}

Did I want a PwS there, or did I just forget {get/set}?

Marking the protocol with an attribute or declmodifier would solve that.

-Chris

···

On Jan 11, 2016, at 3:46 PM, Trent Nadeau <tanadeau@gmail.com> wrote:

Syntactically, would PwS be special like class-only protocols are now or would it be automatic by having stored property declarations within the protocol?


(Trent Nadeau) #12

Syntactically, would PwS be special like class-only protocols are now or
would it be automatic by having stored property declarations within the
protocol?

···

On Mon, Jan 11, 2016 at 6:36 PM, Wallacy via swift-evolution < swift-evolution@swift.org> wrote:

FWIW:

I quick look of my code base (in ObjC), i found 39 code points with I use
ObjC associated objects, one of them is a crazy database manager (for
postgres) with automatic look for the database, search the tables, search
for the program to find classes with the same name, and automatic add a
observer for all rows properties that match (surprisingly works).

Others codes are more simpler, but my point with this proposal, despite
all technical issues, is avoid some "to much creative" solutions to model
the code, one in particular I am looking now (in swift), has 8 core data
properties, and 8 transient and irrelevante properties just to maintain the
everything sane (like avplayer Periodic Time Observer), and all 8 has
default implementation using extensions, will be good declare some of the
storage properties in a protocol and make each "behavior" (like monitoring
the avplayer) a protocol to be reused.

And think about the PwS noted by Chris, yes, maybe can be confusing add
another "kind" of protocols, but like the Self requirement, generally, if
well implemented, its just a matter of time (not so much) to people
understand and drive a good protocol-oriented-programing code.

Em seg, 11 de jan de 2016 às 16:35, Douglas Gregor <dgregor@apple.com> > escreveu:

> On Jan 11, 2016, at 10:27 AM, Chris Lattner <clattner@apple.com> wrote:
>
> On Jan 10, 2016, at 8:34 PM, Douglas Gregor via swift-evolution < >> swift-evolution@swift.org> wrote:
>> 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.
>>
>> 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.
>
> Hi Doug,
>
> Have you considered this similar-but-different approach?

Not this particular shade, but I understand your motivation.

>
> - Allow extensions on classes (only) within the same module/resilience
domain as the class to add stored properties. This would keep them inline
in the instance.
> - Allow protocols to have stored property declarations, introducing a
new “protocol with storage” (PwS) concept.
> - Classes can directly conform to a PwS in its definition, or within an
extension inside the same module/resilience domain.
>
> Just this would give many of the benefits of a full mix-in programming
model. People could define these protocols, and their local implementation
of the type can benefit from them. It doesn’t support retroactive
mixin’ing, but that is probably a good thing. I’m assuming that we don’t
want to allow adding state to structs within a resilience domain, just
because I don’t think that is actually a good thing to add to the
programming model (other reasonable people will surely disagree).
>
> This base model could then be extended:
> - Structs could conform to a PwS in their definition, but not an
extension. We could optionally require the struct to redeclare the
properties to improve readability of the struct, but it wouldn’t be
required from an implementation perspective.
> - Classes could conform to a PwS across resilience boundaries, but
wouldn’t get the state: they’d have to implement the storage requirement
with a computed property.
> - We could introduce an “associated objects” property behavior that
makes providing the computed property very straight-forward, using the out
of band implementation approach of ObjC.
>
> The advantages of this approach I see are:
>
> 1) implementable, always a bonus.

This isn’t a different from my proposal in that regard :wink:

> 2) keeps predictable performance. You don’t get out “associated
objects” overhead unexpectedly. All state is always stored inline.
> 3) retroactive mixins are possible, but explicit.

… this is the real benefit, and I agree. The overhead of associated
objects should require one to explicitly opt-in.

> The primary downside of this approach is that it introduces yet another
weird protocol variant with limitations and behaviors, making the model
more complicated.

I think these semantics are reasonable, and the limitation is the same as
what I proposed: it’s hard to describe why the limitations are what they
are without a deep-dive into the implementation model.

        - Doug

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

--
Trent Nadeau


(Matthew Johnson) #13

Syntactically, would PwS be special like class-only protocols are now or would it be automatic by having stored property declarations within the protocol?

Up for debate. An automatic approach brings hesitation to me, because I don’t want it to be the difference between:

protocol P {
var x : Int { get }
}

and:

protocol P {
var x : Int
}

Did I want a PwS there, or did I just forget {get/set}?

Marking the protocol with an attribute or declmodifier would solve that.

+1. This is something that deserves to be pretty explicit.

Another point that I think needs to be discussed is whether the protocol storage is just a default that can be overridden or whether it should be protocol-specific. Or should the protocol author be able to choose. For example, can a protocol have private storage that is not visible outside the implementation of default or extension methods? All things that need to be considered IMO.

Matthew

···

On Jan 11, 2016, at 7:25 PM, Chris Lattner via swift-evolution <swift-evolution@swift.org> wrote:

On Jan 11, 2016, at 3:46 PM, Trent Nadeau <tanadeau@gmail.com> wrote:

-Chris
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Trent Nadeau) #14

+1 for being explicit given there are, at a minimum, costs to size of
conforming types.

When it comes to visibility to only extensions, that could be more general
that just for protocols. That could also be useful for structs and classes.

For example,

class Foo {
    /// Extensions should log all commands
    // Treated like private everywhere but extensions.
    // It would be an exported symbol but with qualifiers restricting usage
    private public(extension) func logCommand(message: String) { ... }
}

// Can be in another file in same or different module
extension Foo {
    func doStuff() {
        logCommand("Doing stuff now")
        // ...
    }
}

let f = Foo()
f.logCommand("blah") // error anywhere but same file

···

On Mon, Jan 11, 2016 at 8:27 PM, Matthew Johnson <matthew@anandabits.com> wrote:

> On Jan 11, 2016, at 7:25 PM, Chris Lattner via swift-evolution < > swift-evolution@swift.org> wrote:
>
>
>> On Jan 11, 2016, at 3:46 PM, Trent Nadeau <tanadeau@gmail.com> wrote:
>>
>> Syntactically, would PwS be special like class-only protocols are now
or would it be automatic by having stored property declarations within the
protocol?
>
> Up for debate. An automatic approach brings hesitation to me, because I
don’t want it to be the difference between:
>
> protocol P {
> var x : Int { get }
> }
>
> and:
>
> protocol P {
> var x : Int
> }
>
> Did I want a PwS there, or did I just forget {get/set}?
>
> Marking the protocol with an attribute or declmodifier would solve that.

+1. This is something that deserves to be pretty explicit.

Another point that I think needs to be discussed is whether the protocol
storage is just a default that can be overridden or whether it should be
protocol-specific. Or should the protocol author be able to choose. For
example, can a protocol have private storage that is not visible outside
the implementation of default or extension methods? All things that need
to be considered IMO.

Matthew

>
> -Chris
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

--
Trent Nadeau


(Brent Royal-Gordon) #15

An automatic approach brings hesitation to me, because I don’t want it to be the difference between:

protocol P {
var x : Int { get }
}

and:

protocol P {
var x : Int
}

Did I want a PwS there, or did I just forget {get/set}?

If we're going to start adding concrete things to protocols—not just stored properties, but (drawing on other proposals) perhaps also default implementations, final members, factory initializers, etc.—perhaps we should start marking the things that *aren't* concrete with `required`.

Currently:

  public protocol Strideable : Comparable, _Strideable {
      associatedtype Stride : SignedNumberType
      @warn_unused_result
      public func distanceTo(other: Self) -> Self.Stride
      @warn_unused_result
      public func advancedBy(n: Self.Stride) -> Self
  }
  
  extension Strideable {
      @warn_unused_result
      public func stride(to end: Self, by stride: Self.Stride) -> StrideTo<Self> {
          /* implementation here */
      }
  }
  
  extension Strideable {
      @warn_unused_result
      public func stride(through end: Self, by stride: Self.Stride) -> StrideThrough<Self> {
          /* implementation here */
      }
  }

Future:

  public protocol Strideable : Comparable, _Strideable {
      associatedtype Stride : SignedNumberType
      @warn_unused_result
      required public func distanceTo(other: Self) -> Self.Stride
      @warn_unused_result
      required public func advancedBy(n: Self.Stride) -> Self
      
      @warn_unused_result
      final public func stride(to end: Self, by stride: Self.Stride) -> StrideTo<Self> {
          /* implementation here */
      }
            
      @warn_unused_result
      final public func stride(through end: Self, by stride: Self.Stride) -> StrideThrough<Self> {
          /* implementation here */
      }
  }

···

--
Brent Royal-Gordon
Architechies


(Matthew Johnson) #16

An automatic approach brings hesitation to me, because I don’t want it to be the difference between:

protocol P {
var x : Int { get }
}

and:

protocol P {
var x : Int
}

Did I want a PwS there, or did I just forget {get/set}?

If we're going to start adding concrete things to protocols—not just stored properties, but (drawing on other proposals) perhaps also default implementations, final members, factory initializers, etc.—perhaps we should start marking the things that *aren't* concrete with `required`.

Currently:

   public protocol Strideable : Comparable, _Strideable {
       associatedtype Stride : SignedNumberType
       @warn_unused_result
       public func distanceTo(other: Self) -> Self.Stride
       @warn_unused_result
       public func advancedBy(n: Self.Stride) -> Self
   }
   
   extension Strideable {
       @warn_unused_result
       public func stride(to end: Self, by stride: Self.Stride) -> StrideTo<Self> {
           /* implementation here */
       }
   }
   
   extension Strideable {
       @warn_unused_result
       public func stride(through end: Self, by stride: Self.Stride) -> StrideThrough<Self> {
           /* implementation here */
       }
   }

Future:

   public protocol Strideable : Comparable, _Strideable {
       associatedtype Stride : SignedNumberType
       @warn_unused_result
       required public func distanceTo(other: Self) -> Self.Stride
       @warn_unused_result
       required public func advancedBy(n: Self.Stride) -> Self
       
       @warn_unused_result
       final public func stride(to end: Self, by stride: Self.Stride) -> StrideTo<Self> {
           /* implementation here */
       }

       @warn_unused_result
       final public func stride(through end: Self, by stride: Self.Stride) -> StrideThrough<Self> {
           /* implementation here */
       }
   }

Not sure which should be the default (required or not required), but I agree that the minimum required members for conformance should be much more clear than it is in protocol declarations today.

Matthew

···

Sent from my iPad
On Jan 12, 2016, at 1:11 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Wallacy) #17

Yes, currently is hard to "know for sure" if you need for implement all
requirements of the protocol. Usually I wait for compile to tell me.

Anyway, i think the protocols is more useful to model behaviour, and
default implementation help with that. Its like multiple inheritance
without the hard part.

So I'm very concerned about putting "a lot of stuffs" on protocols, and
bring the bad parts of multiple heritage.

Although my proposal, I believe protocols need to be extremely simple, and
easy to use. And i'm really think the storage properties can help with
that. I'm worried about the idea of people using/modeling protocols just as
concrete types.

If this idea go ahead, it may be an opportunity to bring some clarity to
the current scenario, but also prevent future abuses.

The main problem is (to me): What is really a Protocol Oriented Programing?
I Saw Dave Abrahams presentations a few times, but the whole idea is not
100% clear. So it's hard to think of a design to help this concept.

···

Em ter, 12 de jan de 2016 às 05:11, Brent Royal-Gordon via swift-evolution < swift-evolution@swift.org> escreveu:

> An automatic approach brings hesitation to me, because I don’t want it
to be the difference between:
>
> protocol P {
> var x : Int { get }
> }
>
> and:
>
> protocol P {
> var x : Int
> }
>
> Did I want a PwS there, or did I just forget {get/set}?

If we're going to start adding concrete things to protocols—not just
stored properties, but (drawing on other proposals) perhaps also default
implementations, final members, factory initializers, etc.—perhaps we
should start marking the things that *aren't* concrete with `required`.

Currently:

        public protocol Strideable : Comparable, _Strideable {
            associatedtype Stride : SignedNumberType
            @warn_unused_result
            public func distanceTo(other: Self) -> Self.Stride
            @warn_unused_result
            public func advancedBy(n: Self.Stride) -> Self
        }

        extension Strideable {
            @warn_unused_result
            public func stride(to end: Self, by stride: Self.Stride) ->
StrideTo<Self> {
                /* implementation here */
            }
        }

        extension Strideable {
            @warn_unused_result
            public func stride(through end: Self, by stride: Self.Stride)
-> StrideThrough<Self> {
                /* implementation here */
            }
        }

Future:

        public protocol Strideable : Comparable, _Strideable {
            associatedtype Stride : SignedNumberType
            @warn_unused_result
            required public func distanceTo(other: Self) -> Self.Stride
            @warn_unused_result
            required public func advancedBy(n: Self.Stride) -> Self

            @warn_unused_result
            final public func stride(to end: Self, by stride: Self.Stride)
-> StrideTo<Self> {
                /* implementation here */
            }

            @warn_unused_result
            final public func stride(through end: Self, by stride:
Self.Stride) -> StrideThrough<Self> {
                /* implementation here */
            }
        }

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Wallacy) #18

Also, FWIW:

Another example using Dave's presentation:

extension Renderer where Self:CGContext { // same as extension CGContext :
Renderer in this case
   * var defaultDashPhase:CGFloat = 0.0*
* var defaultDashLengths:[CGFloat] = [10.0, 4.0]*

    func moveTo(position: CGPoint) {
        CGContextMoveToPoint(self, position.x, position.y)
    }
    func lineTo(position: CGPoint) {
        CGContextAddLineToPoint(self, position.x, position.y)
    }
    *func dashedLineTo(position: CGPoint) {*

···

*
CGContextSetLineDash(self,defaultDashPhase,defaultDashLengths,defaultDashLengths.count);*
* CGContextAddLineToPoint(self, position.x, position.y)*
* }*
    func arcAt(center: CGPoint, radius: CGFloat, startAngle: CGFloat,
endAngle: CGFloat) {
        let arc = CGPathCreateMutable()
        CGPathAddArc(arc, nil, center.x, center.y, radius, startAngle,
endAngle, true)
        CGContextAddPath(self, arc)
    }
}

We can make more "customizable" extensions, good... And for other "kind" of
Renderer we can use other variables (for that kind), fine.

It's too much magic i know, but i can see some problems be solved using
this construct. But i don't know how to make this more explicit on protocol
declaration, or just leave in that way, like the other functions.

Em ter, 12 de jan de 2016 às 13:32, Wallacy <wallacyf@gmail.com> escreveu:

Yes, currently is hard to "know for sure" if you need for implement all
requirements of the protocol. Usually I wait for compile to tell me.

Anyway, i think the protocols is more useful to model behaviour, and
default implementation help with that. Its like multiple inheritance
without the hard part.

So I'm very concerned about putting "a lot of stuffs" on protocols, and
bring the bad parts of multiple heritage.

Although my proposal, I believe protocols need to be extremely simple, and
easy to use. And i'm really think the storage properties can help with
that. I'm worried about the idea of people using/modeling protocols just as
concrete types.

If this idea go ahead, it may be an opportunity to bring some clarity to
the current scenario, but also prevent future abuses.

The main problem is (to me): What is really a Protocol Oriented
Programing? I Saw Dave Abrahams presentations a few times, but the whole
idea is not 100% clear. So it's hard to think of a design to help this
concept.

Em ter, 12 de jan de 2016 às 05:11, Brent Royal-Gordon via swift-evolution > <swift-evolution@swift.org> escreveu:

> An automatic approach brings hesitation to me, because I don’t want it
to be the difference between:
>
> protocol P {
> var x : Int { get }
> }
>
> and:
>
> protocol P {
> var x : Int
> }
>
> Did I want a PwS there, or did I just forget {get/set}?

If we're going to start adding concrete things to protocols—not just
stored properties, but (drawing on other proposals) perhaps also default
implementations, final members, factory initializers, etc.—perhaps we
should start marking the things that *aren't* concrete with `required`.

Currently:

        public protocol Strideable : Comparable, _Strideable {
            associatedtype Stride : SignedNumberType
            @warn_unused_result
            public func distanceTo(other: Self) -> Self.Stride
            @warn_unused_result
            public func advancedBy(n: Self.Stride) -> Self
        }

        extension Strideable {
            @warn_unused_result
            public func stride(to end: Self, by stride: Self.Stride) ->
StrideTo<Self> {
                /* implementation here */
            }
        }

        extension Strideable {
            @warn_unused_result
            public func stride(through end: Self, by stride: Self.Stride)
-> StrideThrough<Self> {
                /* implementation here */
            }
        }

Future:

        public protocol Strideable : Comparable, _Strideable {
            associatedtype Stride : SignedNumberType
            @warn_unused_result
            required public func distanceTo(other: Self) -> Self.Stride
            @warn_unused_result
            required public func advancedBy(n: Self.Stride) -> Self

            @warn_unused_result
            final public func stride(to end: Self, by stride:
Self.Stride) -> StrideTo<Self> {
                /* implementation here */
            }

            @warn_unused_result
            final public func stride(through end: Self, by stride:
Self.Stride) -> StrideThrough<Self> {
                /* implementation here */
            }
        }

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution