Reputation: 8118
I'm having an array of objects. Now I want to force that those objects are implementing Comparable.
So I created a protocol like this:
protocol Foo: Comparable { }
Everything goes fine except when I create the array:
let array: [Foo] = [obj1, ..]
Then suddenly the compiler complains:
Protocol 'Foo' can only be used as a generic constraint because it has Self or associated type
requirements
Is there another way to do this?
EDIT
class View: UIView {
let viewModel: SomeViewModel
}
class SomeViewModel {
let views: [UIView]
}
Upvotes: 2
Views: 46
Reputation: 299345
Generally when people add this conformance, they're trying to do something like sort a [Foo]
or find the minimum value, but that won't work, even if you could make this Array, because Comparable requires that a type be comparable to its own type, not to others matching the protocol. So for, example, given your array
, you couldn't use array.min()
to find the minimum element, because Comparable does not require that a Foo be comparable to a Foo, only that things that conform to Foo can be compared to themselves.
Instead, you need to extend the protocol to require that conforming types are able to compare themselves against any Foo:
protocol Foo: Comparable {
// ... existing requirements
func isEqual(to: Foo) -> Bool
func isLessThan(_: Foo) -> Bool
}
Given those, you can construct whatever other algorithms you need. You can't use the default forms of contains
or sorted
, but you can use these functions in the where
and by
parameters.
You can also make this a little nicer by providing some default implementations:
extension Foo where Self: Equatable {
func isEqual(to other: Foo) -> Bool {
guard let other = other as? Self else {
return false
}
return self == other
}
}
And similarly for isLessThan
.
And if you want things like contains
, you can then also provide helpers if that's convenient:
extension Sequence where Element == Foo {
func contains(_ element: Element) -> Bool {
return contains(where: { $0.isEqual(to: element) })
}
}
If you want a much longer version of this discussion, see Generic Swift: It Isn't Supposed to Hurt. This particular subject comes up at 37:40.
Upvotes: 1