# Protocol requirement \`where\` clauses constraining associated types

**URL:** <https://forums.swift.org/t/protocol-requirement-where-clauses-constraining-associated-types/5133>\
**Category:** Discussion\
**Created:** [February 9, 2017, 5:57am UTC](https://forums.swift.org/t/protocol-requirement-where-clauses-constraining-associated-types/5133 "2017-02-09T05:57:56Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Brent\_Royal-Gordon](https://avatars.discourse-cdn.com/v4/letter/b/53a042/32.png) [@Brent\_Royal-Gordon](https://forums.swift.org/u/Brent_Royal-Gordon)\
**Post date:** [February 9, 2017, 5:57am UTC](https://forums.swift.org/t/protocol-requirement-where-clauses-constraining-associated-types/5133/1 "2017-02-09T05:57:56Z")

</div>

In an article on `Collection` today\*, Ole Begemann points out that `index(of:)`, along with other `Equatable`- and `Comparable`-constrained `Collection` methods, cannot be overridden. Actually, it \*can\* be, but only through a private mechanism—there's a `_customIndexOfEquatableElement(_:)` method that's invisible in the generated interface. But that only proves the need for a way to make methods like these overridable.

The problem is that the `index(of:)` method should only be offered when the element is `Equatable`—otherwise it simply won't work. But there's no way to specify this rule in current Swift. In theory, we could describe such a requirement with something like this:

&nbsp;&nbsp;func index(of element: Iterator.Element) -\> Index? where Iterator.Element: Equatable

But this is not permitted—you get an error indicating that `where` clauses are only allowed on generic methods. Adding a spurious generic parameter allows this code to compile, but with a deprecation warning indicating that this is deprecated. I don't know if it would actually behave correctly, however.

Is this a feature we should add? Is this the way to add it? Would it have non-additive ABI impact? (The private `index(of:)` override would certainly go away, but that's why it's private, I suppose.) I don't seem to remember seeing something like this in the generics manifesto, so I thought it was worth bringing up.

\* [A Sorted Array Implementation in Swift – Ole Begemann](https://oleb.net/blog/2017/02/sorted-array/)

> **···**
>
> --  
> Brent Royal-Gordon  
> Architechies

---

<div class="post-metadata">

**Author:** ![Slava\_Pestov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/slava_pestov/32/30204_2.png) [@Slava\_Pestov](https://forums.swift.org/u/Slava_Pestov)\
**Post date:** [February 9, 2017, 6:21am UTC](https://forums.swift.org/t/protocol-requirement-where-clauses-constraining-associated-types/5133/2 "2017-02-09T06:21:20Z")

</div>

Hah, Doug and I were just discussing this.

In Swift 3.1, we generalized where clauses to allow them to add requirements on outer generic parameters. However we did not remove the diagnostic prohibiting a where clause from being attached to a non-generic method. In theory this can be made to work; the only slightly tricky thing is we will get a GenericParamList with zero parameters but non-zero requirements, which would require shuffling some things around to avoid assertions.

This would be a good starter project for someone who wanted to learn more about the generics system.

As for index(of:) and the specific details of the stdlib that are involved here, I have no idea — I’m just talking about the bogus diagnostic itself.

Slava

> **···**
>
> > On Feb 8, 2017, at 9:57 PM, Brent Royal-Gordon via swift-evolution \<swift-evolution@swift.org\> wrote:
> > 
> > In an article on `Collection` today\*, Ole Begemann points out that `index(of:)`, along with other `Equatable`- and `Comparable`-constrained `Collection` methods, cannot be overridden. Actually, it \*can\* be, but only through a private mechanism—there's a `_customIndexOfEquatableElement(_:)` method that's invisible in the generated interface. But that only proves the need for a way to make methods like these overridable.
> > 
> > The problem is that the `index(of:)` method should only be offered when the element is `Equatable`—otherwise it simply won't work. But there's no way to specify this rule in current Swift. In theory, we could describe such a requirement with something like this:
> > 
> > &nbsp;&nbsp;func index(of element: Iterator.Element) -\> Index? where Iterator.Element: Equatable
> > 
> > But this is not permitted—you get an error indicating that `where` clauses are only allowed on generic methods. Adding a spurious generic parameter allows this code to compile, but with a deprecation warning indicating that this is deprecated. I don't know if it would actually behave correctly, however.
> > 
> > Is this a feature we should add? Is this the way to add it? Would it have non-additive ABI impact? (The private `index(of:)` override would certainly go away, but that's why it's private, I suppose.) I don't seem to remember seeing something like this in the generics manifesto, so I thought it was worth bringing up.
> > 
> > \* [A Sorted Array Implementation in Swift – Ole Begemann](https://oleb.net/blog/2017/02/sorted-array/)
> > 
> > --  
> > Brent Royal-Gordon  
> > Architechies
> > 
> > \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_  
> > swift-evolution mailing list  
> > swift-evolution@swift.org  
> > [https://lists.swift.org/mailman/listinfo/swift-evolution](https://lists.swift.org/mailman/listinfo/swift-evolution)

---

<div class="post-metadata">

**Author:** ![Douglas\_Gregor](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/douglas_gregor/32/1362_2.png) [@Douglas\_Gregor](https://forums.swift.org/u/Douglas_Gregor)\
**Post date:** [February 9, 2017, 6:30am UTC](https://forums.swift.org/t/protocol-requirement-where-clauses-constraining-associated-types/5133/3 "2017-02-09T06:30:25Z")

</div>

> Hah, Doug and I were just discussing this.
> 
> In Swift 3.1, we generalized where clauses to allow them to add requirements on outer generic parameters. However we did not remove the diagnostic prohibiting a where clause from being attached to a non-generic method. In theory this can be made to work; the only slightly tricky thing is we will get a GenericParamList with zero parameters but non-zero requirements, which would require shuffling some things around to avoid assertions.
> 
> This would be a good starter project for someone who wanted to learn more about the generics system.
> 
> As for index(of:) and the specific details of the stdlib that are involved here, I have no idea — I’m just talking about the bogus diagnostic itself.

Well, I think Brent is talking about doing this on a protocol requirement, which is more interesting because not all conforming types would satisfy the requirement...

&nbsp;&nbsp;- Doug

> **···**
>
> > On Feb 8, 2017, at 10:21 PM, Slava Pestov \<spestov@apple.com\> wrote:
> 
> > Slava
> > 
> > > On Feb 8, 2017, at 9:57 PM, Brent Royal-Gordon via swift-evolution \<swift-evolution@swift.org\> wrote:
> > > 
> > > In an article on `Collection` today\*, Ole Begemann points out that `index(of:)`, along with other `Equatable`- and `Comparable`-constrained `Collection` methods, cannot be overridden. Actually, it \*can\* be, but only through a private mechanism—there's a `_customIndexOfEquatableElement(_:)` method that's invisible in the generated interface. But that only proves the need for a way to make methods like these overridable.
> > > 
> > > The problem is that the `index(of:)` method should only be offered when the element is `Equatable`—otherwise it simply won't work. But there's no way to specify this rule in current Swift. In theory, we could describe such a requirement with something like this:
> > > 
> > > &nbsp;&nbsp;func index(of element: Iterator.Element) -\> Index? where Iterator.Element: Equatable
> > > 
> > > But this is not permitted—you get an error indicating that `where` clauses are only allowed on generic methods. Adding a spurious generic parameter allows this code to compile, but with a deprecation warning indicating that this is deprecated. I don't know if it would actually behave correctly, however.
> > > 
> > > Is this a feature we should add? Is this the way to add it? Would it have non-additive ABI impact? (The private `index(of:)` override would certainly go away, but that's why it's private, I suppose.) I don't seem to remember seeing something like this in the generics manifesto, so I thought it was worth bringing up.
> > > 
> > > \* [A Sorted Array Implementation in Swift – Ole Begemann](https://oleb.net/blog/2017/02/sorted-array/)
> > > 
> > > --  
> > > Brent Royal-Gordon  
> > > Architechies
> > > 
> > > \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_  
> > > swift-evolution mailing list  
> > > swift-evolution@swift.org  
> > > [https://lists.swift.org/mailman/listinfo/swift-evolution](https://lists.swift.org/mailman/listinfo/swift-evolution)

---

<div class="post-metadata">

**Author:** ![dabrahams](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dabrahams/32/9815_2.png) [@dabrahams](https://forums.swift.org/u/dabrahams)\
**Post date:** [February 9, 2017, 7:37am UTC](https://forums.swift.org/t/protocol-requirement-where-clauses-constraining-associated-types/5133/4 "2017-02-09T07:37:17Z")

</div>

Funny thing; Nate Cook and I were just discussing the same thing today.  
It seems like this hack we did in the standard library points to a  
missing language feature; one with possible ABI impact.

> **···**
>
> on Wed Feb 08 2017, Slava Pestov \<swift-evolution@swift.org\> wrote:
> 
> > Hah, Doug and I were just discussing this.
> 
> --  
> -Dave

---

<div class="post-metadata">

**Author:** ![Slava\_Pestov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/slava_pestov/32/30204_2.png) [@Slava\_Pestov](https://forums.swift.org/u/Slava_Pestov)\
**Post date:** [February 9, 2017, 7:12am UTC](https://forums.swift.org/t/protocol-requirement-where-clauses-constraining-associated-types/5133/5 "2017-02-09T07:12:39Z")

</div>

> > Hah, Doug and I were just discussing this.
> > 
> > In Swift 3.1, we generalized where clauses to allow them to add requirements on outer generic parameters. However we did not remove the diagnostic prohibiting a where clause from being attached to a non-generic method. In theory this can be made to work; the only slightly tricky thing is we will get a GenericParamList with zero parameters but non-zero requirements, which would require shuffling some things around to avoid assertions.
> > 
> > This would be a good starter project for someone who wanted to learn more about the generics system.
> > 
> > As for index(of:) and the specific details of the stdlib that are involved here, I have no idea — I’m just talking about the bogus diagnostic itself.
> 
> Well, I think Brent is talking about doing this on a protocol requirement, which is more interesting because not all conforming types would satisfy the requirement…

Since there would be no way to invoke the requirement on such a type, could we leave the entry blank in the witness table or emit a fatalError() thunk or something?

Slava

> **···**
>
> > On Feb 8, 2017, at 10:30 PM, Douglas Gregor \<dgregor@apple.com\> wrote:
> > 
> > > On Feb 8, 2017, at 10:21 PM, Slava Pestov \<spestov@apple.com\> wrote:
> 
> > &nbsp;&nbsp;- Doug
> > 
> > > Slava
> > > 
> > > > On Feb 8, 2017, at 9:57 PM, Brent Royal-Gordon via swift-evolution \<swift-evolution@swift.org\> wrote:
> > > > 
> > > > In an article on `Collection` today\*, Ole Begemann points out that `index(of:)`, along with other `Equatable`- and `Comparable`-constrained `Collection` methods, cannot be overridden. Actually, it \*can\* be, but only through a private mechanism—there's a `_customIndexOfEquatableElement(_:)` method that's invisible in the generated interface. But that only proves the need for a way to make methods like these overridable.
> > > > 
> > > > The problem is that the `index(of:)` method should only be offered when the element is `Equatable`—otherwise it simply won't work. But there's no way to specify this rule in current Swift. In theory, we could describe such a requirement with something like this:
> > > > 
> > > > &nbsp;&nbsp;func index(of element: Iterator.Element) -\> Index? where Iterator.Element: Equatable
> > > > 
> > > > But this is not permitted—you get an error indicating that `where` clauses are only allowed on generic methods. Adding a spurious generic parameter allows this code to compile, but with a deprecation warning indicating that this is deprecated. I don't know if it would actually behave correctly, however.
> > > > 
> > > > Is this a feature we should add? Is this the way to add it? Would it have non-additive ABI impact? (The private `index(of:)` override would certainly go away, but that's why it's private, I suppose.) I don't seem to remember seeing something like this in the generics manifesto, so I thought it was worth bringing up.
> > > > 
> > > > \* [A Sorted Array Implementation in Swift – Ole Begemann](https://oleb.net/blog/2017/02/sorted-array/)
> > > > 
> > > > --  
> > > > Brent Royal-Gordon  
> > > > Architechies
> > > > 
> > > > \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_  
> > > > swift-evolution mailing list  
> > > > swift-evolution@swift.org  
> > > > [https://lists.swift.org/mailman/listinfo/swift-evolution](https://lists.swift.org/mailman/listinfo/swift-evolution)

---

<div class="post-metadata">

**Author:** ![Douglas\_Gregor](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/douglas_gregor/32/1362_2.png) [@Douglas\_Gregor](https://forums.swift.org/u/Douglas_Gregor)\
**Post date:** [February 9, 2017, 3:03pm UTC](https://forums.swift.org/t/protocol-requirement-where-clauses-constraining-associated-types/5133/6 "2017-02-09T15:03:06Z")

</div>

> > > Hah, Doug and I were just discussing this.
> > > 
> > > In Swift 3.1, we generalized where clauses to allow them to add requirements on outer generic parameters. However we did not remove the diagnostic prohibiting a where clause from being attached to a non-generic method. In theory this can be made to work; the only slightly tricky thing is we will get a GenericParamList with zero parameters but non-zero requirements, which would require shuffling some things around to avoid assertions.
> > > 
> > > This would be a good starter project for someone who wanted to learn more about the generics system.
> > > 
> > > As for index(of:) and the specific details of the stdlib that are involved here, I have no idea — I’m just talking about the bogus diagnostic itself.
> > 
> > Well, I think Brent is talking about doing this on a protocol requirement, which is more interesting because not all conforming types would satisfy the requirement…
> 
> Since there would be no way to invoke the requirement on such a type, could we leave the entry blank in the witness table or emit a fatalError() thunk or something?

I’d previously thought so, but retroactive modeling makes this more interesting than that:

&nbsp;&nbsp;// Module A  
&nbsp;&nbsp;public protocol P { }  
&nbsp;&nbsp;public protocol Q {  
&nbsp;&nbsp;&nbsp;&nbsp;associatedtype Assoc

&nbsp;&nbsp;&nbsp;&nbsp;func f() where Assoc: P  
&nbsp;&nbsp;}

&nbsp;&nbsp;public struct X { }

&nbsp;&nbsp;public struct Y : Q {  
&nbsp;&nbsp;&nbsp;&nbsp;public typealias Assoc = X

&nbsp;&nbsp;&nbsp;&nbsp;// X doesn’t conform to P, so I guess we can omit f()?  
&nbsp;&nbsp;}

&nbsp;&nbsp;public func callF\<T: Q\>(t: T) where T.Assoc: P {  
&nbsp;&nbsp;&nbsp;&nbsp;t.f() // should be allowed to call f() because we know that T.Assoc conforms to P  
&nbsp;&nbsp;}

&nbsp;&nbsp;// Module B  
&nbsp;&nbsp;public extension X: P { }

&nbsp;&nbsp;callF(Y()) // BOOM at runtime, because witness table Y: Q doesn’t include f!

So, I think that means we can’t just leave a stub there

&nbsp;&nbsp;// Back in module A  
&nbsp;&nbsp;public struct Z : Q {  
&nbsp;&nbsp;&nbsp;&nbsp;public typealias Assoc = X

&nbsp;&nbsp;&nbsp;&nbsp;public func f() where X: P { } // wait, what?  
&nbsp;&nbsp;}

That last one is “fun”. The method “f()" is only available when the concrete type X conforms to P. We know it doesn’t right now—but it could in the future. It’s a bit odd to reason about such a function, because you’re evaluating how the concrete type X would behave if it did in fact conform to P! In Swift-compiler-speak, it’s a concrete type with an abstract conformance to P, which is a bit of a model breaker.

&nbsp;&nbsp;- Doug

> **···**
>
> > On Feb 8, 2017, at 11:12 PM, Slava Pestov \<spestov@apple.com\> wrote:
> > 
> > > On Feb 8, 2017, at 10:30 PM, Douglas Gregor \<dgregor@apple.com\> wrote:
> > > 
> > > > On Feb 8, 2017, at 10:21 PM, Slava Pestov \<spestov@apple.com\> wrote:
> 
> > Slava
> > 
> > > &nbsp;&nbsp;- Doug
> > > 
> > > > Slava
> > > > 
> > > > > On Feb 8, 2017, at 9:57 PM, Brent Royal-Gordon via swift-evolution \<swift-evolution@swift.org\> wrote:
> > > > > 
> > > > > In an article on `Collection` today\*, Ole Begemann points out that `index(of:)`, along with other `Equatable`- and `Comparable`-constrained `Collection` methods, cannot be overridden. Actually, it \*can\* be, but only through a private mechanism—there's a `_customIndexOfEquatableElement(_:)` method that's invisible in the generated interface. But that only proves the need for a way to make methods like these overridable.
> > > > > 
> > > > > The problem is that the `index(of:)` method should only be offered when the element is `Equatable`—otherwise it simply won't work. But there's no way to specify this rule in current Swift. In theory, we could describe such a requirement with something like this:
> > > > > 
> > > > > &nbsp;&nbsp;func index(of element: Iterator.Element) -\> Index? where Iterator.Element: Equatable
> > > > > 
> > > > > But this is not permitted—you get an error indicating that `where` clauses are only allowed on generic methods. Adding a spurious generic parameter allows this code to compile, but with a deprecation warning indicating that this is deprecated. I don't know if it would actually behave correctly, however.
> > > > > 
> > > > > Is this a feature we should add? Is this the way to add it? Would it have non-additive ABI impact? (The private `index(of:)` override would certainly go away, but that's why it's private, I suppose.) I don't seem to remember seeing something like this in the generics manifesto, so I thought it was worth bringing up.
> > > > > 
> > > > > \* [A Sorted Array Implementation in Swift – Ole Begemann](https://oleb.net/blog/2017/02/sorted-array/)
> > > > > 
> > > > > --  
> > > > > Brent Royal-Gordon  
> > > > > Architechies
> > > > > 
> > > > > \_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_\_  
> > > > > swift-evolution mailing list  
> > > > > swift-evolution@swift.org  
> > > > > [https://lists.swift.org/mailman/listinfo/swift-evolution](https://lists.swift.org/mailman/listinfo/swift-evolution)
