The only method that is used on the victims parameter is contains. So while the original use case had a Set handy, there's cases where I'd like to just be able to use an Array there as well. So I thought I would modify the method to be more general. Since contains comes from the Sequence protocol that Set conforms to, I tried:
Which isn't really helpful for me personally. But I tried it with just Sequence as well. Which just produces the:
Protocol 'Sequence' can only be used as a generic constraint because it has Self or associated type requirements
Can one not have an arbitrary collection type as a parameter? What simple syntax twist am I missing? Or do I just have to have to pick a concrete collection type and force all call sites to create that specific type if need be?
What you're seeing here is a restriction because Sequence is a protocol with associated types. There's a distinction between generic protocols, i.e. 'A sequence of ValveSpans', and protocols with associated types, which is asking for 'a type that is a Sequence whose Element is ValveSpan'. Your intuition, 'do I just have to have to pick a concrete collection type' is almost correct; you can use generics to write a function that accepts any type that conforms to the Sequence protocol whose Element is ValveSpan.
The syntax for this is:
func purging<VictimSequence: Sequence>(_ victims: VictimSequence) where VictimSequence.Element == ValveSpan
Thank you! I had to figure out where the -> return type goes... BEFORE the where clause apparently.
If I have a bunch of methods that all work with arbitrary collections of ValveSpans, is there some way to make a protocol type that represents "an arbitrary collection of ValveSpans" that DOES NOT have the problem of associated types? Or do I have to repeat this boilerplate generics everywhere?
(I have read the generics section twice; but to date, I find I still really struggle with Swift's generics stuff)
We don't yet support defining such a protocol as a type, but you have a couple of options for expressing these operations. You could make them methods in an extension on Sequence:
extension Sequence where Element == ValveSpan {
func purging(_ victims: Self) -> Self { ... }
}
Or you can define a protocol that refines Sequence and adds a constraint:
protocol ValveSpanSequence: Sequence where Element == ValveSpan {}
extension Array: ValveSpanSequence where Element == ValveSpan {}
func purging<S: ValveSpanSequence>(_ victims: S) -> S { ... }