Skip to content

[StdLib][RFC][DNM] Add isIdentical Methods for Quick Comparisons to Array, ArraySlice, and ContiguousArray #82438

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

vanvoorden
Copy link
Contributor

@vanvoorden vanvoorden commented Jun 23, 2025

Background

swiftlang/swift-evolution#2875

We propose new isIdentical instance methods to the following concrete types for determining in constant-time if two instances must be equal by-value:

  • String
  • Substring
  • Array
  • ArraySlice
  • ContiguousArray
  • Dictionary
  • Set

Instead of “one big diff”… we can try and keep the diffs grouped together by similar functionality:

  • String, Substring
  • Array, ArraySlice, ContiguousArray
  • Dictionary, Set

Changes

Our Array already performs a "fast path" for equality checking in our == operator.1 We can implement a similar check for isIdentical:

extension Array {
  @_alwaysEmitIntoClient
  public func isIdentical(to other: Self) -> Bool {
    let lhsCount = self.count
    if lhsCount != other.count {
      return false
    }

    // Test referential equality.
    if unsafe lhsCount == 0 || self._buffer.identity == other._buffer.identity {
      return true
    }
    
    return false
  }
}

There are similar fast paths in ArraySlice and ContiguousArray.23

Test Plan

TODO

Benchmarks

TODO

Footnotes

  1. https://github.com/swiftlang/swift/blob/swift-6.1.2-RELEASE/stdlib/public/core/Array.swift#L1816-L1824

  2. https://github.com/swiftlang/swift/blob/swift-6.1.2-RELEASE/stdlib/public/core/ArraySlice.swift#L1398-L1406

  3. https://github.com/swiftlang/swift/blob/swift-6.1.2-RELEASE/stdlib/public/core/ContiguousArray.swift#L1335-L1343

/// identical.
///
/// - Performance: O(1)
@backDeployed(before: SwiftStdlib 6.3)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer this (and everything else in this PR) to be @_alwaysEmitIntoClient instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Azoy TBH… I have zero experience with either option. From reading through SE-0376 it sounds like backDeployed came with some advantages:

While @_alwaysEmitIntoClient can be used to back deploy APIs, there are some drawbacks to using it. Since a copy of the function is always emitted, there is code size overhead for every client even if the client's deployment target is new enough that the library API would always be available at runtime. Additionally, if the implementation of the API were to change in order to improve performance, fix a bug, or close a security hole then the client would need to be recompiled against a new SDK before users benefit from those changes.

I don't see much discussion in that proposal over when a library maintainer would still prefer _alwaysEmitIntoClient.

I did find this discussion from @lorentey:

#75433 (comment)

It sounds like one issue here was that debugDescription was used to conform to a protocol. Our isIdentical function here would not be used to conform to a protocol. It sounds like that might make safer shipping backDeployed?

But we did leave a FIXME comment:

e39613b

That we eventually want to make this backDeployed.

Hmm… would you have any more specific ideas why we prefer _alwaysEmitIntoClient here for these changes?

Copy link
Contributor

@Azoy Azoy Jun 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because @backDeployed commits this as the stdlib's ABI vs. @_aEIC which does not. If we find we need to replace this in the future with some more generalized thing or such, we pay the price of having to maintain this forever instead of just being able to update the definition. @_aEIC is the best attribute in my opinion because it is the "pay for what you use" attribute both for the stdlib and the client. The stdlib doesn't have to take the code size hit (unless it started using it in its own opaque implementation) or the ABI hit, and clients don't pay for anything unless they use it themselves or use something that uses it.

There's also the fact that @backDeployed introduces a runtime availability check for some configurations which does have a performance cost vs. @_aEIC which does not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Azoy SGTM. I'll make the changes and push a new commit. Thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Azoy would you have any opinion about #82055 and #82439? Same tradeoff for preferring aEIC on those?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants