[Proposal] More Powerful Constraints for Associated Types


(David Hart) #1

I wrote the proposal which was discussed to introduce generic constraints for associated types. I’d like to get some feedback on it and get it ready before submitting it:

More Powerful Constraints for Associated Types

Proposal: SE-XXXX <https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md>
Author(s): David Hart <http://github.com/hartbit>
Status: TBD
Review manager: TBD
<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#introduction>Introduction

This proposal seeks to introduce a where expression to associated types declarations to bring the same expressive power as generic type constraints.

This proposal was discussed on the Swift Evolution list in the [swift-evolution] [Completing Generics] Arbitrary requirements in protocols <http://thread.gmane.org/gmane.comp.lang.swift.evolution/14243> thread.

<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#motivation>Motivation

Currently, associated type declarations can only express simple inheritance constraints and not the more sophisticated constraints available to generic types with the where expression. Some designs, including many in the Standard Library, require more powerful constraints for associated types to be truly elegant. For example, the SequenceType protocol can be declared as follows:

protocol Sequence {
    associatedtype Iterator : IteratorProtocol
    associatedtype SubSequence : Sequence where SubSequence.Iterator.Element == Iterator.Element
    ...
}
<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#detail-design>Detail Design

With this proposal, the grammar for protocols associated types would be modified to:

protocol-associated-type-declaration → attributesopt access-level-modifieropt associatedtype typealias-name ­type-inheritance-clause­opt­ typealias-assignment­opt requirement-clauseopt

The new requirement-clause is then used by the compiler to validate the associated types of conforming types.

<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#issues>Issues

Douglas Gregor argues that the proposed syntax is redundant when adding new constraints to an associated type declared in a parent protocol and proposes another syntax:

protocol Collection : Sequence {
    where SubSequence : Collection
}
But as Douglas notes himself, that syntax will become ambiguous if we adopt the generic where expression at the end of declarations like discussed in the following thread: http://thread.gmane.org/gmane.comp.lang.swift.evolution/13886/focus=14058. For those reasons, it might be wiser not to introduce the shorthand syntax.

<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#acknowledgements>Acknowledgements

Thanks to Dave Abrahams and Douglas Gregor for taking the time to help me through this proposal.


(Dmitri Gribenko) #2

I completely support this. This feature will unblock many
improvements in the standard library. Currently users of some
protocols have to carry extra constraints in their own type
signatures, but we should be able to hoist these constraints into the
protocol definiton.

Dmitri

···

On Sun, Apr 24, 2016 at 1:34 PM, David Hart via swift-evolution <swift-evolution@swift.org> wrote:

Currently, associated type declarations can only express simple inheritance
constraints and not the more sophisticated constraints available to generic
types with the where expression. Some designs, including many in the
Standard Library, require more powerful constraints for associated types to
be truly elegant. For example, the SequenceType protocol can be declared as
follows:

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Matthew Johnson) #3

I really like this proposal. It is a nice step forward from current state.

However, it looks like it doesn't allow us to express constraints that elate two or more associated types together, such as requiring both to have the same Element type. I think it would be a good idea to solve the general problem of constraining associated types if possible. The general case is an important part of completing generics IMO so it should be within the scope of Swift 3 to consider it.

Matthew

···

Sent from my iPad

On Apr 24, 2016, at 3:34 PM, David Hart via swift-evolution <swift-evolution@swift.org> wrote:

I wrote the proposal which was discussed to introduce generic constraints for associated types. I’d like to get some feedback on it and get it ready before submitting it:

More Powerful Constraints for Associated Types
Proposal: SE-XXXX
Author(s): David Hart
Status: TBD
Review manager: TBD
Introduction

This proposal seeks to introduce a where expression to associated types declarations to bring the same expressive power as generic type constraints.

This proposal was discussed on the Swift Evolution list in the [swift-evolution] [Completing Generics] Arbitrary requirements in protocols thread.

Motivation

Currently, associated type declarations can only express simple inheritance constraints and not the more sophisticated constraints available to generic types with the where expression. Some designs, including many in the Standard Library, require more powerful constraints for associated types to be truly elegant. For example, the SequenceType protocol can be declared as follows:

protocol Sequence {
    associatedtype Iterator : IteratorProtocol
    associatedtype SubSequence : Sequence where SubSequence.Iterator.Element == Iterator.Element
    ...
}
Detail Design

With this proposal, the grammar for protocols associated types would be modified to:

protocol-associated-type-declaration → attributesopt access-level-modifieropt associatedtype typealias-name ­type-inheritance-clause­opt­ typealias-assignment­opt requirement-clauseopt

The new requirement-clause is then used by the compiler to validate the associated types of conforming types.

Issues

Douglas Gregor argues that the proposed syntax is redundant when adding new constraints to an associated type declared in a parent protocol and proposes another syntax:

protocol Collection : Sequence {
    where SubSequence : Collection
}
But as Douglas notes himself, that syntax will become ambiguous if we adopt the generic where expression at the end of declarations like discussed in the following thread: http://thread.gmane.org/gmane.comp.lang.swift.evolution/13886/focus=14058. For those reasons, it might be wiser not to introduce the shorthand syntax.

Acknowledgements

Thanks to Dave Abrahams and Douglas Gregor for taking the time to help me through this proposal.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Haravikk) #4

I’m a strong +1 for this, although I’m suspicious of the timing as in my current project I could do with this right now :wink:

···

On 24 Apr 2016, at 21:34, David Hart via swift-evolution <swift-evolution@swift.org> wrote:

I wrote the proposal which was discussed to introduce generic constraints for associated types. I’d like to get some feedback on it and get it ready before submitting it:

More Powerful Constraints for Associated Types

Proposal: SE-XXXX <https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md>
Author(s): David Hart <http://github.com/hartbit>
Status: TBD
Review manager: TBD
<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#introduction>Introduction

This proposal seeks to introduce a where expression to associated types declarations to bring the same expressive power as generic type constraints.

This proposal was discussed on the Swift Evolution list in the [swift-evolution] [Completing Generics] Arbitrary requirements in protocols <http://thread.gmane.org/gmane.comp.lang.swift.evolution/14243> thread.

<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#motivation>Motivation

Currently, associated type declarations can only express simple inheritance constraints and not the more sophisticated constraints available to generic types with the where expression. Some designs, including many in the Standard Library, require more powerful constraints for associated types to be truly elegant. For example, the SequenceType protocol can be declared as follows:

protocol Sequence {
    associatedtype Iterator : IteratorProtocol
    associatedtype SubSequence : Sequence where SubSequence.Iterator.Element == Iterator.Element
    ...
}
<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#detail-design>Detail Design

With this proposal, the grammar for protocols associated types would be modified to:

protocol-associated-type-declaration → attributesopt access-level-modifieropt associatedtype typealias-name ­type-inheritance-clause­opt­ typealias-assignment­opt requirement-clauseopt

The new requirement-clause is then used by the compiler to validate the associated types of conforming types.

<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#issues>Issues

Douglas Gregor argues that the proposed syntax is redundant when adding new constraints to an associated type declared in a parent protocol and proposes another syntax:

protocol Collection : Sequence {
    where SubSequence : Collection
}
But as Douglas notes himself, that syntax will become ambiguous if we adopt the generic where expression at the end of declarations like discussed in the following thread: http://thread.gmane.org/gmane.comp.lang.swift.evolution/13886/focus=14058. For those reasons, it might be wiser not to introduce the shorthand syntax.

<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#acknowledgements>Acknowledgements

Thanks to Dave Abrahams and Douglas Gregor for taking the time to help me through this proposal.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Rod Brown) #5

I'm definitely a supporter of this change. It addresses things I've hit multiple times.

···

On 25 Apr 2016, at 6:34 AM, David Hart via swift-evolution <swift-evolution@swift.org> wrote:

I wrote the proposal which was discussed to introduce generic constraints for associated types. I’d like to get some feedback on it and get it ready before submitting it:

More Powerful Constraints for Associated Types
Proposal: SE-XXXX
Author(s): David Hart
Status: TBD
Review manager: TBD
Introduction

This proposal seeks to introduce a where expression to associated types declarations to bring the same expressive power as generic type constraints.

This proposal was discussed on the Swift Evolution list in the [swift-evolution] [Completing Generics] Arbitrary requirements in protocols thread.

Motivation

Currently, associated type declarations can only express simple inheritance constraints and not the more sophisticated constraints available to generic types with the where expression. Some designs, including many in the Standard Library, require more powerful constraints for associated types to be truly elegant. For example, the SequenceType protocol can be declared as follows:

protocol Sequence {
    associatedtype Iterator : IteratorProtocol
    associatedtype SubSequence : Sequence where SubSequence.Iterator.Element == Iterator.Element
    ...
}
Detail Design

With this proposal, the grammar for protocols associated types would be modified to:

protocol-associated-type-declaration → attributesopt access-level-modifieropt associatedtype typealias-name ­type-inheritance-clause­opt­ typealias-assignment­opt requirement-clauseopt

The new requirement-clause is then used by the compiler to validate the associated types of conforming types.

Issues

Douglas Gregor argues that the proposed syntax is redundant when adding new constraints to an associated type declared in a parent protocol and proposes another syntax:

protocol Collection : Sequence {
    where SubSequence : Collection
}
But as Douglas notes himself, that syntax will become ambiguous if we adopt the generic where expression at the end of declarations like discussed in the following thread: http://thread.gmane.org/gmane.comp.lang.swift.evolution/13886/focus=14058. For those reasons, it might be wiser not to introduce the shorthand syntax.

Acknowledgements

Thanks to Dave Abrahams and Douglas Gregor for taking the time to help me through this proposal.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Douglas Gregor) #6

I wrote the proposal which was discussed to introduce generic constraints for associated types. I’d like to get some feedback on it and get it ready before submitting it:

More Powerful Constraints for Associated Types

Proposal: SE-XXXX <https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md>
Author(s): David Hart <http://github.com/hartbit>
Status: TBD
Review manager: TBD
<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#introduction>Introduction

This proposal seeks to introduce a where expression to associated types declarations to bring the same expressive power as generic type constraints.

This proposal was discussed on the Swift Evolution list in the [swift-evolution] [Completing Generics] Arbitrary requirements in protocols <http://thread.gmane.org/gmane.comp.lang.swift.evolution/14243> thread.

Believe it or not, I support this direction…

<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#motivation>Motivation

Currently, associated type declarations can only express simple inheritance constraints and not the more sophisticated constraints available to generic types with the where expression. Some designs, including many in the Standard Library, require more powerful constraints for associated types to be truly elegant. For example, the SequenceType protocol can be declared as follows:

protocol Sequence {
    associatedtype Iterator : IteratorProtocol
    associatedtype SubSequence : Sequence where SubSequence.Iterator.Element == Iterator.Element
    ...
}
<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#detail-design>Detail Design

With this proposal, the grammar for protocols associated types would be modified to:

protocol-associated-type-declaration → attributesopt access-level-modifieropt associatedtype typealias-name ­type-inheritance-clause­opt­ typealias-assignment­opt requirement-clauseopt

The new requirement-clause is then used by the compiler to validate the associated types of conforming types.

The only thing that bothers me about this syntax is that I have to introduce an associated type to add requirements. For example, what if I want my inheriting protocol to add a requirement to an existing associated type?

protocol P { }

protocol Q {
  typealias AssocType
}

protocol R : Q {
  // I want to just add “AssocType : P”, but I have to redeclare AssocType to do so
  typealias AssocType where AssocType : P
}

Did you consider an alternate syntax that puts the where clause outside the braces, e.g.,

protocol R : Q where AssocType : P {
  // …
}

There are two things I like about this. First, it breaks the unnecessary link between an associated type and a (possibly unrelated) where clause, eliminating the need to redeclare associated types in inheriting protocols. Second, it’s effectively the same syntax as constrained extensions, which have a similar feel.

Note that, if we do the above, I’d love to make it an error to define a new associated type with the same name as an associated type in an inherited protocol. It’s odd that we do so, and IIRC the only use case for it is to add requirement to an “existing” associated type.

  - Doug

···

On Apr 24, 2016, at 1:34 PM, David Hart via swift-evolution <swift-evolution@swift.org> wrote:


(James Richard) #7

+1 to this! I’ve been missing this as well.


(David Hart) #8

I’ve updated the proposal with comments from the discussions and opened a pull request. Please let me know if you have any feedback before it’s merged:

More Powerful Constraints for Associated Types

Proposal: SE-XXXX <https://github.com/apple/swift-evolution/blob/master/proposals/XXXX-associated-types-constraints.md>
Author(s): David Hart <http://github.com/hartbit>, Jacob Bandes-Storch <https://github.com/hartbit/swift-evolution/blob/associated-types-constraints/proposals/jtbandes@gmail.com>, Douglas Gregor <https://github.com/hartbit/swift-evolution/blob/associated-types-constraints/proposals/dgregor@apple.com>
Status: TBD
Review manager: TBD
<https://github.com/hartbit/swift-evolution/blob/associated-types-constraints/proposals/XXXX-associated-types-constraints.md#introduction>Introduction

This proposal seeks to introduce a where clause to associated types declarations to bring the same expressive power as generic type constraints.

This proposal was discussed twice on the Swift Evolution list in the following threads:

[Completing Generics] Arbitrary requirements in protocols <http://thread.gmane.org/gmane.comp.lang.swift.evolution/14243>
More Powerful Constraints for Associated Types <http://thread.gmane.org/gmane.comp.lang.swift.evolution/15201>
<https://github.com/hartbit/swift-evolution/blob/associated-types-constraints/proposals/XXXX-associated-types-constraints.md#motivation>Motivation

Currently, associated type declarations can only express simple inheritance constraints and not the more sophisticated constraints available to generic types with the where clause. Some designs, including many in the Standard Library, require more powerful constraints for associated types to be truly elegant. For example, the SequenceType protocol can be declared as follows:

protocol Sequence {
    associatedtype Iterator : IteratorProtocol
    associatedtype SubSequence : Sequence where SubSequence.Iterator.Element == Iterator.Element
    ...
}
<https://github.com/hartbit/swift-evolution/blob/associated-types-constraints/proposals/XXXX-associated-types-constraints.md#detail-design>Detail Design

With this proposal, the grammar for protocols associated types would be modified to:

protocol-associated-type-declaration → attributesopt access-level-modifieropt associatedtype typealias-name ­type-inheritance-clause­opt typealias-assignment­opt requirement-clauseopt

The new requirement-clause is then used by the compiler to validate the associated types of conforming types.

The proposal also allows protocols to use the associated types of their conforming protocols in their declaration where clause as below:

protocol IntSequence : Sequence where Iterator.Element == Int {
    ...
}
<https://github.com/hartbit/swift-evolution/blob/associated-types-constraints/proposals/XXXX-associated-types-constraints.md#alternatives>Alternatives

Douglas Gregor argues that the proposed syntax is redundant when adding new constraints to an associated type declared in a parent protocol and proposes another syntax:

protocol Collection : Sequence {
    where SubSequence : Collection
}
But as Douglas notes himself, that syntax will become ambiguous if we adopt the generic where clause at the end of declarations like discussed in proposal SE-0081: Move where clause to end of declaration <https://github.com/apple/swift-evolution/blob/master/proposals/0081-move-where-expression.md>. For those reasons, it might be wiser not to introduce the shorthand syntax.

<https://github.com/hartbit/swift-evolution/blob/associated-types-constraints/proposals/XXXX-associated-types-constraints.md#acknowledgements>Acknowledgements

Thanks to Dave Abrahams and Douglas Gregor for taking the time to help me through this proposal.


(Thorsten Seitz) #9

+1
I've been missing this myself

-Thorsten

···

Am 25.04.2016 um 04:15 schrieb Rod Brown via swift-evolution <swift-evolution@swift.org>:

I'm definitely a supporter of this change. It addresses things I've hit multiple times.

On 25 Apr 2016, at 6:34 AM, David Hart via swift-evolution <swift-evolution@swift.org> wrote:

I wrote the proposal which was discussed to introduce generic constraints for associated types. I’d like to get some feedback on it and get it ready before submitting it:

More Powerful Constraints for Associated Types
Proposal: SE-XXXX
Author(s): David Hart
Status: TBD
Review manager: TBD
Introduction

This proposal seeks to introduce a where expression to associated types declarations to bring the same expressive power as generic type constraints.

This proposal was discussed on the Swift Evolution list in the [swift-evolution] [Completing Generics] Arbitrary requirements in protocols thread.

Motivation

Currently, associated type declarations can only express simple inheritance constraints and not the more sophisticated constraints available to generic types with the where expression. Some designs, including many in the Standard Library, require more powerful constraints for associated types to be truly elegant. For example, the SequenceType protocol can be declared as follows:

protocol Sequence {
    associatedtype Iterator : IteratorProtocol
    associatedtype SubSequence : Sequence where SubSequence.Iterator.Element == Iterator.Element
    ...
}
Detail Design

With this proposal, the grammar for protocols associated types would be modified to:

protocol-associated-type-declaration → attributesopt access-level-modifieropt associatedtype typealias-name ­type-inheritance-clause­opt­ typealias-assignment­opt requirement-clauseopt

The new requirement-clause is then used by the compiler to validate the associated types of conforming types.

Issues

Douglas Gregor argues that the proposed syntax is redundant when adding new constraints to an associated type declared in a parent protocol and proposes another syntax:

protocol Collection : Sequence {
    where SubSequence : Collection
}
But as Douglas notes himself, that syntax will become ambiguous if we adopt the generic where expression at the end of declarations like discussed in the following thread: http://thread.gmane.org/gmane.comp.lang.swift.evolution/13886/focus=14058. For those reasons, it might be wiser not to introduce the shorthand syntax.

Acknowledgements

Thanks to Dave Abrahams and Douglas Gregor for taking the time to help me through this proposal.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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


(Dave Abrahams) #10

+1

···

on Mon Apr 25 2016, Dmitri Gribenko <swift-evolution@swift.org> wrote:

On Sun, Apr 24, 2016 at 1:34 PM, David Hart via swift-evolution > <swift-evolution@swift.org> wrote:

Currently, associated type declarations can only express simple inheritance
constraints and not the more sophisticated constraints available to generic
types with the where expression. Some designs, including many in the
Standard Library, require more powerful constraints for associated types to
be truly elegant. For example, the SequenceType protocol can be declared as
follows:

I completely support this. This feature will unblock many
improvements in the standard library. Currently users of some
protocols have to carry extra constraints in their own type
signatures, but we should be able to hoist these constraints into the
protocol definiton.

--
Dave


(Thorsten Seitz) #11

I really like this proposal. It is a nice step forward from current state.

However, it looks like it doesn't allow us to express constraints that elate two or more associated types together, such as requiring both to have the same Element type.

Did I miss something? I thought that was the exact example given in the motivation section?

-Thorsten

···

Am 25.04.2016 um 15:40 schrieb Matthew Johnson via swift-evolution <swift-evolution@swift.org>:

I think it would be a good idea to solve the general problem of constraining associated types if possible. The general case is an important part of completing generics IMO so it should be within the scope of Swift 3 to consider it.

Matthew

Sent from my iPad

On Apr 24, 2016, at 3:34 PM, David Hart via swift-evolution <swift-evolution@swift.org> wrote:

I wrote the proposal which was discussed to introduce generic constraints for associated types. I’d like to get some feedback on it and get it ready before submitting it:

More Powerful Constraints for Associated Types
Proposal: SE-XXXX
Author(s): David Hart
Status: TBD
Review manager: TBD
Introduction

This proposal seeks to introduce a where expression to associated types declarations to bring the same expressive power as generic type constraints.

This proposal was discussed on the Swift Evolution list in the [swift-evolution] [Completing Generics] Arbitrary requirements in protocols thread.

Motivation

Currently, associated type declarations can only express simple inheritance constraints and not the more sophisticated constraints available to generic types with the where expression. Some designs, including many in the Standard Library, require more powerful constraints for associated types to be truly elegant. For example, the SequenceType protocol can be declared as follows:

protocol Sequence {
    associatedtype Iterator : IteratorProtocol
    associatedtype SubSequence : Sequence where SubSequence.Iterator.Element == Iterator.Element
    ...
}
Detail Design

With this proposal, the grammar for protocols associated types would be modified to:

protocol-associated-type-declaration → attributesopt access-level-modifieropt associatedtype typealias-name ­type-inheritance-clause­opt­ typealias-assignment­opt requirement-clauseopt

The new requirement-clause is then used by the compiler to validate the associated types of conforming types.

Issues

Douglas Gregor argues that the proposed syntax is redundant when adding new constraints to an associated type declared in a parent protocol and proposes another syntax:

protocol Collection : Sequence {
    where SubSequence : Collection
}
But as Douglas notes himself, that syntax will become ambiguous if we adopt the generic where expression at the end of declarations like discussed in the following thread: http://thread.gmane.org/gmane.comp.lang.swift.evolution/13886/focus=14058. For those reasons, it might be wiser not to introduce the shorthand syntax.

Acknowledgements

Thanks to Dave Abrahams and Douglas Gregor for taking the time to help me through this proposal.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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


(Dmitri Gribenko) #12

To me this reads like declaring a conditional conformance.

Dmitri

···

On Mon, Apr 25, 2016 at 8:28 PM, Douglas Gregor via swift-evolution <swift-evolution@swift.org> wrote:

Did you consider an alternate syntax that puts the where clause outside the
braces, e.g.,

protocol R : Q where AssocType : P {
  // …
}

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(Brent Royal-Gordon) #13

Note that, if we do the above, I’d love to make it an error to define a new associated type with the same name as an associated type in an inherited protocol. It’s odd that we do so, and IIRC the only use case for it is to add requirement to an “existing” associated type.

You also do it to specify or change a default associated type. This is from an older copy of the stdlib source code, but I believe there's still something equivalent:

  public protocol CollectionType : Indexable, SequenceType {
    associatedtype Generator: GeneratorType = IndexingGenerator<Self>

···

--
Brent Royal-Gordon
Architechies


(David Hart) #14

Hi Doug,

In the latest version of the proposal, which is now linked to a pull request, I mentioned in the Detail Design section that the following syntax be valid:

protocol R : Q where AssocType : P {
  // …
}

Can you read through that part of the proposal and let me know if it is descriptive enough?

David.

···

On 26 Apr 2016, at 05:28, Douglas Gregor <dgregor@apple.com> wrote:

On Apr 24, 2016, at 1:34 PM, David Hart via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I wrote the proposal which was discussed to introduce generic constraints for associated types. I’d like to get some feedback on it and get it ready before submitting it:

More Powerful Constraints for Associated Types

Proposal: SE-XXXX <https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md>
Author(s): David Hart <http://github.com/hartbit>
Status: TBD
Review manager: TBD
<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#introduction>Introduction

This proposal seeks to introduce a where expression to associated types declarations to bring the same expressive power as generic type constraints.

This proposal was discussed on the Swift Evolution list in the [swift-evolution] [Completing Generics] Arbitrary requirements in protocols <http://thread.gmane.org/gmane.comp.lang.swift.evolution/14243> thread.

Believe it or not, I support this direction…

<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#motivation>Motivation

Currently, associated type declarations can only express simple inheritance constraints and not the more sophisticated constraints available to generic types with the where expression. Some designs, including many in the Standard Library, require more powerful constraints for associated types to be truly elegant. For example, the SequenceType protocol can be declared as follows:

protocol Sequence {
    associatedtype Iterator : IteratorProtocol
    associatedtype SubSequence : Sequence where SubSequence.Iterator.Element == Iterator.Element
    ...
}
<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#detail-design>Detail Design

With this proposal, the grammar for protocols associated types would be modified to:

protocol-associated-type-declaration → attributesopt access-level-modifieropt associatedtype typealias-name ­type-inheritance-clause­opt­ typealias-assignment­opt requirement-clauseopt

The new requirement-clause is then used by the compiler to validate the associated types of conforming types.

The only thing that bothers me about this syntax is that I have to introduce an associated type to add requirements. For example, what if I want my inheriting protocol to add a requirement to an existing associated type?

protocol P { }

protocol Q {
  typealias AssocType
}

protocol R : Q {
  // I want to just add “AssocType : P”, but I have to redeclare AssocType to do so
  typealias AssocType where AssocType : P
}

Did you consider an alternate syntax that puts the where clause outside the braces, e.g.,

protocol R : Q where AssocType : P {
  // …
}

There are two things I like about this. First, it breaks the unnecessary link between an associated type and a (possibly unrelated) where clause, eliminating the need to redeclare associated types in inheriting protocols. Second, it’s effectively the same syntax as constrained extensions, which have a similar feel.

Note that, if we do the above, I’d love to make it an error to define a new associated type with the same name as an associated type in an inherited protocol. It’s odd that we do so, and IIRC the only use case for it is to add requirement to an “existing” associated type.

  - Doug


(Matthew Johnson) #15

I really like this proposal. It is a nice step forward from current state.

However, it looks like it doesn't allow us to express constraints that elate two or more associated types together, such as requiring both to have the same Element type.

Did I miss something? I thought that was the exact example given in the motivation section?

You are right. I'm not sure how I missed that. I think it is because the constraints are attached to a single associatedtype declaration rather than being at the top level of the protocol declaration.

It feels slightly awkward to have to attach such constraints to one of the associatedtype declarations as they are effectively peers in the same type constraint. Allowing such constraints to stand alone would look similar to Doug's example in the issues section. I would prefer to look for a syntax for generic constraints on declarations that allows for freestanding and refined constraints in protocols.

···

Sent from my iPad

On Apr 25, 2016, at 9:58 AM, Thorsten Seitz <tseitz42@icloud.com> wrote:

Am 25.04.2016 um 15:40 schrieb Matthew Johnson via swift-evolution <swift-evolution@swift.org>:

-Thorsten

I think it would be a good idea to solve the general problem of constraining associated types if possible. The general case is an important part of completing generics IMO so it should be within the scope of Swift 3 to consider it.

Matthew

Sent from my iPad

On Apr 24, 2016, at 3:34 PM, David Hart via swift-evolution <swift-evolution@swift.org> wrote:

I wrote the proposal which was discussed to introduce generic constraints for associated types. I’d like to get some feedback on it and get it ready before submitting it:

More Powerful Constraints for Associated Types
Proposal: SE-XXXX
Author(s): David Hart
Status: TBD
Review manager: TBD
Introduction

This proposal seeks to introduce a where expression to associated types declarations to bring the same expressive power as generic type constraints.

This proposal was discussed on the Swift Evolution list in the [swift-evolution] [Completing Generics] Arbitrary requirements in protocols thread.

Motivation

Currently, associated type declarations can only express simple inheritance constraints and not the more sophisticated constraints available to generic types with the where expression. Some designs, including many in the Standard Library, require more powerful constraints for associated types to be truly elegant. For example, the SequenceType protocol can be declared as follows:

protocol Sequence {
    associatedtype Iterator : IteratorProtocol
    associatedtype SubSequence : Sequence where SubSequence.Iterator.Element == Iterator.Element
    ...
}
Detail Design

With this proposal, the grammar for protocols associated types would be modified to:

protocol-associated-type-declaration → attributesopt access-level-modifieropt associatedtype typealias-name ­type-inheritance-clause­opt­ typealias-assignment­opt requirement-clauseopt

The new requirement-clause is then used by the compiler to validate the associated types of conforming types.

Issues

Douglas Gregor argues that the proposed syntax is redundant when adding new constraints to an associated type declared in a parent protocol and proposes another syntax:

protocol Collection : Sequence {
    where SubSequence : Collection
}
But as Douglas notes himself, that syntax will become ambiguous if we adopt the generic where expression at the end of declarations like discussed in the following thread: http://thread.gmane.org/gmane.comp.lang.swift.evolution/13886/focus=14058. For those reasons, it might be wiser not to introduce the shorthand syntax.

Acknowledgements

Thanks to Dave Abrahams and Douglas Gregor for taking the time to help me through this proposal.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

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


(Tony Allevato) #16

I really like where this proposal is headed.

Would this syntax also support constraining associated types based on
"inheritability" (for lack of a better word)? For example, a couple times
I've hit a situation where I want to express a supertype/subtype
relationship. A contrived example:

protocol Foo {
  associatedtype Bar

  func f<Baz: Bar>(b: Baz.Type) -> Baz
}

This currently gives me the error "inheritance from non-protocol, non-class
type 'Self.Bar'." This makes sense in a way, because a type conforming to
Foo could define Bar to be anything, including a struct.

I see a few ways to address this:

(1) Allow users to write "associatedtype Bar: class" to indicate that the
conforming class must set Bar to be a class type, which would let the type
checker know that the Baz: Bar constraint is valid. This gets us partially
there, but is still somewhat limiting because other supertype/subtype
relationships could not be expressed, such as Bar being an arbitrary
protocol and Baz being any type that conforms to that protocol.

(2) Allow users to write "associatedtype Bar: _____", where _____ is some
way of expressing any arbitrary type that is inheritable: this would
include classes but also protocols. The difference here is instead of
specifying a specific protocol, conforming types could put any protocol
here, binding Bar in function f() to that protocol and then Baz would be
any type conforming to Bar.

(3) Allow the syntax above unchanged. If a conforming type defines Bar to
be a struct, loosen the check and still allow it such that the only
possible type that can satisfy Baz is Bar itself. This would be consistent
with other generic constraints that are class-based, where a constraint of
the form f<SomeClass: BaseClass> can still satisfy SomeClass by using
BaseClass itself.

While writing this, I noticed some other constructs that seem like they
should work, but don't:

protocol SomeProtocol {}
protocol Foo {
  associatedtype Bar: SomeProtocol
  func f<Baz: Bar>(b: Baz.Type) -> Baz
  // ^ inheritance from non-protocol, non-class type 'Self.Bar'
  // Shouldn't the compiler know that Bar is constrained by a protocol here?
}

class SomeClass {}
protocol Foo {
  associatedtype Bar: SomeClass
  func f<Baz: Bar>(b: Baz.Type) -> Baz
  // ^ inheritance from non-protocol, non-class type 'Self.Bar'
  // Same problem as above, essentially.
}

protocol A {}
protocol B {}
protocol Foo {
  associatedtype Bar: protocol<A, B>
  // ^ This one doesn't appear to even get past the parser, which is
unfortunate.
  // To express the notion of an associatedtype conforming to two
protocols, you
  // have to create a third protocol and extend the type you wish to use to
conform
  // to that protocol.
}

Some of these issues may have been addressed in "Completing generics", but
they seem like they would fit into this proposal as well.

···

On Mon, Apr 25, 2016 at 8:30 AM Matthew Johnson via swift-evolution < swift-evolution@swift.org> wrote:

Sent from my iPad

On Apr 25, 2016, at 9:58 AM, Thorsten Seitz <tseitz42@icloud.com> wrote:

Am 25.04.2016 um 15:40 schrieb Matthew Johnson via swift-evolution < > swift-evolution@swift.org>:

I really like this proposal. It is a nice step forward from current
state.

However, it looks like it doesn't allow us to express constraints that
elate two or more associated types together, such as requiring both to have
the same Element type.

Did I miss something? I thought that was the exact example given in the
motivation section?

You are right. I'm not sure how I missed that. I think it is because the
constraints are attached to a single associatedtype declaration rather than
being at the top level of the protocol declaration.

It feels slightly awkward to have to attach such constraints to one of the
associatedtype declarations as they are effectively peers in the same type
constraint. Allowing such constraints to stand alone would look similar to
Doug's example in the issues section. I would prefer to look for a syntax
for generic constraints on declarations that allows for freestanding and
refined constraints in protocols.

-Thorsten

I think it would be a good idea to solve the general problem of
constraining associated types if possible. The general case is an
important part of completing generics IMO so it should be within the scope
of Swift 3 to consider it.

Matthew

Sent from my iPad

On Apr 24, 2016, at 3:34 PM, David Hart via swift-evolution < > swift-evolution@swift.org> wrote:

I wrote the proposal which was discussed to introduce generic constraints
for associated types. I’d like to get some feedback on it and get it ready
before submitting it:

More Powerful Constraints for Associated Types

   - Proposal: SE-XXXX
   <https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md>
   - Author(s): David Hart <http://github.com/hartbit>
   - Status: *TBD*
   - Review manager: TBD

<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#introduction>
Introduction

This proposal seeks to introduce a where expression to associated types
declarations to bring the same expressive power as generic type constraints.

*This proposal was discussed on the Swift Evolution list in
the [swift-evolution] [Completing Generics] Arbitrary requirements in
protocols
<http://thread.gmane.org/gmane.comp.lang.swift.evolution/14243> thread.*

<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#motivation>
Motivation

Currently, associated type declarations can only express simple
inheritance constraints and not the more sophisticated constraints
available to generic types with the where expression. Some designs,
including many in the Standard Library, require more powerful constraints
for associated types to be truly elegant. For example, the SequenceType protocol
can be declared as follows:

protocol Sequence {
    associatedtype Iterator : IteratorProtocol
    associatedtype SubSequence : Sequence where SubSequence.Iterator.Element == Iterator.Element
    ...
}

<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#detail-design>Detail
Design

With this proposal, the grammar for protocols associated types would be
modified to:

*protocol-associated-type-declaration* → *attributesopt*
*access-level-modifieropt* *associatedtype* *typealias-name*
*­type-inheritance-clause­opt­* *typealias-assignment­opt*
*requirement-clauseopt*

The new requirement-clause is then used by the compiler to validate the
associated types of conforming types.

<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#issues>
Issues

Douglas Gregor argues that the proposed syntax is redundant when adding
new constraints to an associated type declared in a parent protocol and
proposes another syntax:

protocol Collection : Sequence {
    where SubSequence : Collection
}

But as Douglas notes himself, that syntax will become ambiguous if we
adopt the generic where expression at the end of declarations like
discussed in the following thread:
http://thread.gmane.org/gmane.comp.lang.swift.evolution/13886/focus=14058.
For those reasons, it might be wiser not to introduce the shorthand syntax.

<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#acknowledgements>
Acknowledgements
Thanks to Dave Abrahams and Douglas Gregor for taking the time to help me
through this proposal.

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

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

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


(Douglas Gregor) #17

Did you consider an alternate syntax that puts the where clause outside the
braces, e.g.,

protocol R : Q where AssocType : P {
// …
}

To me this reads like declaring a conditional conformance.

I'm reading it as "R is-a Q where AssocType is-a P".

···

Sent from my iPhone

On Apr 25, 2016, at 8:41 PM, Dmitri Gribenko <gribozavr@gmail.com> wrote:
On Mon, Apr 25, 2016 at 8:28 PM, Douglas Gregor via swift-evolution > <swift-evolution@swift.org> wrote:

Dmitri

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/


(David Sweeris) #18

Is that bad? We already have conditional inheritance in classes:
  class Foo<T where _constraint_> : Bar<T> {}
If you move the where clause to the right:
  class Foo<T> : Bar<T where _constraint_> {}
And drop the generic arguments:
  class Foo : Bar where _constraint_ {}
The only difference is “protocol” vs “class”.

- Dave Sweeris

···

On Apr 25, 2016, at 10:41 PM, Dmitri Gribenko via swift-evolution <swift-evolution@swift.org> wrote:

On Mon, Apr 25, 2016 at 8:28 PM, Douglas Gregor via swift-evolution > <swift-evolution@swift.org> wrote:

Did you consider an alternate syntax that puts the where clause outside the
braces, e.g.,

protocol R : Q where AssocType : P {
// …
}

To me this reads like declaring a conditional conformance.

Dmitri

--
main(i,j){for(i=2;;i++){for(j=2;j<i;j++){if(!(i%j)){j=0;break;}}if
(j){printf("%d\n",i);}}} /*Dmitri Gribenko <gribozavr@gmail.com>*/
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Douglas Gregor) #19

Note that, if we do the above, I’d love to make it an error to define a new associated type with the same name as an associated type in an inherited protocol. It’s odd that we do so, and IIRC the only use case for it is to add requirement to an “existing” associated type.

You also do it to specify or change a default associated type. This is from an older copy of the stdlib source code, but I believe there's still something equivalent:

   public protocol CollectionType : Indexable, SequenceType {
     associatedtype Generator: GeneratorType = IndexingGenerator<Self>

Ah yes, of course! Thank you.

  - Doug

···

Sent from my iPhone
On Apr 25, 2016, at 10:03 PM, Brent Royal-Gordon <brent@architechies.com> wrote:


(David Hart) #20

Hello Tony,

Sorry, I never took the time to comment. I see the issues you are pointing, but they seem to be more generic than only concerning associated type constraints. For example, the "inheritance from non-protocol, non-class type” error also concerns generic types. Perhaps it should be best to start new discussions and new proposal for those issues? This proposal already seems like a mouthful to me.

David.

···

On 25 Apr 2016, at 18:01, Tony Allevato via swift-evolution <swift-evolution@swift.org> wrote:

I really like where this proposal is headed.

Would this syntax also support constraining associated types based on "inheritability" (for lack of a better word)? For example, a couple times I've hit a situation where I want to express a supertype/subtype relationship. A contrived example:

protocol Foo {
  associatedtype Bar

  func f<Baz: Bar>(b: Baz.Type) -> Baz
}

This currently gives me the error "inheritance from non-protocol, non-class type 'Self.Bar'." This makes sense in a way, because a type conforming to Foo could define Bar to be anything, including a struct.

I see a few ways to address this:

(1) Allow users to write "associatedtype Bar: class" to indicate that the conforming class must set Bar to be a class type, which would let the type checker know that the Baz: Bar constraint is valid. This gets us partially there, but is still somewhat limiting because other supertype/subtype relationships could not be expressed, such as Bar being an arbitrary protocol and Baz being any type that conforms to that protocol.

(2) Allow users to write "associatedtype Bar: _____", where _____ is some way of expressing any arbitrary type that is inheritable: this would include classes but also protocols. The difference here is instead of specifying a specific protocol, conforming types could put any protocol here, binding Bar in function f() to that protocol and then Baz would be any type conforming to Bar.

(3) Allow the syntax above unchanged. If a conforming type defines Bar to be a struct, loosen the check and still allow it such that the only possible type that can satisfy Baz is Bar itself. This would be consistent with other generic constraints that are class-based, where a constraint of the form f<SomeClass: BaseClass> can still satisfy SomeClass by using BaseClass itself.

While writing this, I noticed some other constructs that seem like they should work, but don't:

protocol SomeProtocol {}
protocol Foo {
  associatedtype Bar: SomeProtocol
  func f<Baz: Bar>(b: Baz.Type) -> Baz
  // ^ inheritance from non-protocol, non-class type 'Self.Bar'
  // Shouldn't the compiler know that Bar is constrained by a protocol here?
}

class SomeClass {}
protocol Foo {
  associatedtype Bar: SomeClass
  func f<Baz: Bar>(b: Baz.Type) -> Baz
  // ^ inheritance from non-protocol, non-class type 'Self.Bar'
  // Same problem as above, essentially.
}

protocol A {}
protocol B {}
protocol Foo {
  associatedtype Bar: protocol<A, B>
  // ^ This one doesn't appear to even get past the parser, which is unfortunate.
  // To express the notion of an associatedtype conforming to two protocols, you
  // have to create a third protocol and extend the type you wish to use to conform
  // to that protocol.
}

Some of these issues may have been addressed in "Completing generics", but they seem like they would fit into this proposal as well.

On Mon, Apr 25, 2016 at 8:30 AM Matthew Johnson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Sent from my iPad

On Apr 25, 2016, at 9:58 AM, Thorsten Seitz <tseitz42@icloud.com <mailto:tseitz42@icloud.com>> wrote:

Am 25.04.2016 um 15:40 schrieb Matthew Johnson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>>:

I really like this proposal. It is a nice step forward from current state.

However, it looks like it doesn't allow us to express constraints that elate two or more associated types together, such as requiring both to have the same Element type.

Did I miss something? I thought that was the exact example given in the motivation section?

You are right. I'm not sure how I missed that. I think it is because the constraints are attached to a single associatedtype declaration rather than being at the top level of the protocol declaration.

It feels slightly awkward to have to attach such constraints to one of the associatedtype declarations as they are effectively peers in the same type constraint. Allowing such constraints to stand alone would look similar to Doug's example in the issues section. I would prefer to look for a syntax for generic constraints on declarations that allows for freestanding and refined constraints in protocols.

-Thorsten

I think it would be a good idea to solve the general problem of constraining associated types if possible. The general case is an important part of completing generics IMO so it should be within the scope of Swift 3 to consider it.

Matthew

Sent from my iPad

On Apr 24, 2016, at 3:34 PM, David Hart via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I wrote the proposal which was discussed to introduce generic constraints for associated types. I’d like to get some feedback on it and get it ready before submitting it:

More Powerful Constraints for Associated Types

Proposal: SE-XXXX <https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md>
Author(s): David Hart <http://github.com/hartbit>
Status: TBD
Review manager: TBD
<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#introduction>Introduction

This proposal seeks to introduce a where expression to associated types declarations to bring the same expressive power as generic type constraints.

This proposal was discussed on the Swift Evolution list in the [swift-evolution] [Completing Generics] Arbitrary requirements in protocols <http://thread.gmane.org/gmane.comp.lang.swift.evolution/14243> thread.

<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#motivation>Motivation

Currently, associated type declarations can only express simple inheritance constraints and not the more sophisticated constraints available to generic types with the where expression. Some designs, including many in the Standard Library, require more powerful constraints for associated types to be truly elegant. For example, the SequenceType protocol can be declared as follows:

protocol Sequence {
    associatedtype Iterator : IteratorProtocol
    associatedtype SubSequence : Sequence where SubSequence.Iterator.Element == Iterator.Element
    ...
}
<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#detail-design>Detail Design

With this proposal, the grammar for protocols associated types would be modified to:

protocol-associated-type-declaration → attributesopt access-level-modifieropt associatedtype typealias-name ­type-inheritance-clause­opt­ typealias-assignment­opt requirement-clauseopt

The new requirement-clause is then used by the compiler to validate the associated types of conforming types.

<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#issues>Issues

Douglas Gregor argues that the proposed syntax is redundant when adding new constraints to an associated type declared in a parent protocol and proposes another syntax:

protocol Collection : Sequence {
    where SubSequence : Collection
}
But as Douglas notes himself, that syntax will become ambiguous if we adopt the generic where expression at the end of declarations like discussed in the following thread: http://thread.gmane.org/gmane.comp.lang.swift.evolution/13886/focus=14058. For those reasons, it might be wiser not to introduce the shorthand syntax.

<https://github.com/hartbit/swift-evolution/blob/master/proposals/XXXX-powerful-constraints-associated-types.md#acknowledgements>Acknowledgements

Thanks to Dave Abrahams and Douglas Gregor for taking the time to help me through this proposal.
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

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

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