swiftlang / swiftlang/swift-experimental-string-processing
When passing a collection to `Set.contains(_:)`, forward to `Set.isSuperset(of:)`
Nobody has claimed this yet.
- Dominant language
- Swift
- Stars
- 308
- Forks
- 52
- Avg merge
- 12h 45m
- Merged PRs (30d)
- 2
Description
Motivation
There is a confusing behavior of Set.contains(_:) when passing a collection that contains more than one element:
let s: Set = [1, 2, 3]
s.contains([1]) // true
s.contains([1] as Set) // true
s.contains([1, 2]) // false 🤨
s.contains([1, 2] as Set) // false 🤨
s.contains([1, 2, 3]) // false 🤨
s.contains([1, 2, 3] as Set) // false 🤨
I think this confusion is introduced by a Collection extension in the _StringProcessing module:
extension Collection where Self.Element : Equatable {
/// Returns a Boolean value indicating whether the collection contains the
/// given sequence.
/// - Parameter other: A sequence to search for within this collection.
/// - Returns: `true` if the collection contains the specified sequence,
/// otherwise `false`.
@available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *)
public func contains<C>(_ other: C) -> Bool where C : Collection, Self.Element == C.Element
}
I understand that this behavior is caused by the Set internally storing its elements in a random order (as viewed from outside), so checking whether “[…] the collection contains the given sequence” is not really a useful thing to do on a Set, making this method pretty much useless there.
Proposed solution
To make this method useful on Set, it could simply forward to Set.isSuperset(of:), which is what I would have expected in the first place:
s.isSuperset(of: [1, 2]) // true
s.isSuperset(of: [1, 2] as Set) // true
s.isSuperset(of: [1, 2, 3]) // true
s.isSuperset(of: [1, 2, 3] as Set) // true
While maybe not strictly correct in the sense of the documentation that “[…] the collection contains the given sequence” because the order of elements as passed is irrelevant, I think it is more useful because the behavior is at least deterministic.
Alternatives considered
None really. Do nothing and keep the behavior as-is, I guess.
Additional information
I posted on the Swift forum about this and received only one reply that agreed with the confusing behavior.
Here’s the thread: Passing a Collection to Set.contains(_:) leads to confusing results
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at the Collection.contains(_:) extension in the StringProcessing module and compare its sequence semantics with Set.isSuperset(of:). Confirm the desired behavior for single- and multiple-element collections, then add coverage showing that Set.contains(:) behaves deterministically for these cases.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- swift
- Domain
- api
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 38/100