Skip to content

When passing a collection to Set.contains(_:), forward to Set.isSuperset(of:) #796

Open
@marcomasser

Description

@marcomasser

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions