# \[Pitch #2\] Add \`isKnownIdentical\` Method for Quick Comparisons to \`Equatable\`

**URL:** <https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497>\
**Category:** Pitches\
**Created:** [June 16, 2025, 6:00pm UTC](https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497 "2025-06-16T18:00:31Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![vanvoorden](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/vanvoorden/32/33619_2.png) [@vanvoorden](https://forums.swift.org/u/vanvoorden)\
**Post date:** [June 16, 2025, 6:00pm UTC](https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497/1 "2025-06-16T18:00:31Z")

</div>

Hi! Here is a new pitch refined from an earlier one:

> [@\[Pitch\] \`Distinguishable\` protocol for Quick Comparisons](https://forums.swift.org/t/pitch-distinguishable-protocol-for-quick-comparisons/79145):
>
> Hi! Here is a pitch derived from this discussion: Distinguishable protocol and isIdentical Function for Quick Comparisons Introduction I propose a new Distinguishable protocol and isIdentical function for determining if two instances are distinguishable in constant-time. Motivation Suppose we have some code that listens to values from an AsyncSequence. Every value received from the AsyncSequence is then used to perform some work that scales linearly with the size of the Element: func doLine…

# Add `isKnownIdentical` Method for Quick Comparisons to `Equatable`

- Proposal: SE-NNNN
- Authors: [Rick van Voorden](https://github.com/vanvoorden), [Karoy Lorentey](https://github.com/lorentey)
- Review Manager: TBD
- Status: **Awaiting implementation**
- Implementation: TODO
- Review: ([Pre-Pitch](https://forums.swift.org/t/how-to-check-two-array-instances-for-identity-equality-in-constant-time/78792)), ([Pitch #1](https://forums.swift.org/t/pitch-distinguishable-protocol-for-quick-comparisons/79145))

## Introduction

We propose a new `isKnownIdentical` method to `Equatable` for determining in constant-time if two instances must be equal by-value.

## Motivation

Suppose we have some code that listens to elements from an `AsyncSequence`. Every element received from the `AsyncSequence` is then used to perform some work that scales linearly with the size of the element:

```swift
func doLinearOperation<T>(with element: T) {
  // perform some operation
  // scales linearly with T
}

func f1<S>(sequence: S) async throws
where S: AsyncSequence {
  for try await element in sequence {
    doLinearOperation(with: element)
  }
}

```

Suppose we know that `doLinearOperation` only performs important work when `element` is not equal to the last value (here we define “equal” to imply “value equality”). The _first_ call to `doLinearOperation` is important, and the _next_ calls to `doLinearOperation` are only important if `element` is not equal by-value to the last `element` that was used to perform `doLinearOperation`.

If we know that `Element` conforms to `Equatable`, we can choose to “memoize” our values _before_ we perform `doLinearOperation`:

```swift
func f2<S>(sequence: S) async throws
where S: AsyncSequence, S.Element: Equatable {
  var oldElement: S.Element?
  for try await element in sequence {
    if oldElement == element { continue }
    oldElement = element
    doLinearOperation(with: element)
  }
}

```

When our `sequence` produces many elements that are equal by-value, “eagerly” passing that element to `doLinearOperation` performs more work than necessary. Performing a check for value-equality _before_ we pass that element to `doLinearOperation` saves us the work from performing `doLinearOperation` more than necessary, but we have now traded performance in a different direction. Because we know that the work performed in `doLinearOperation` scales linearly with the size of the `element`, and we know that the `==` operator _also_ scales linearly with the size of the `element`, we now perform _two_ linear operations whenever our `sequence` delivers a new `element` that is not equal by-value to the previous input to `doLinearOperation`.

At this point our product engineer has to make a tradeoff: do we “eagerly” perform the call to `doLinearOperation` _without_ a preflight check for value equality on the expectation that `sequence` will produce many non-equal values, or do we perform the call to `doLinearOperation` _with_ a preflight check for value equality on the expectation that `sequence` will produce many equal values?

There is a third path forward… a “quick” check against elements that returns in constant-time and _guarantees_ these instances _must_ be equal by value.

## Prior Art

`Swift.String` already ships a public-but-underscored API that returns in constant time:\[1\]

```swift
extension String {
  /// Returns a boolean value indicating whether this string is identical to
  /// `other`.
  ///
  /// Two string values are identical if there is no way to distinguish between
  /// them.
  ///
  /// Comparing strings this way includes comparing (normally) hidden
  /// implementation details such as the memory location of any underlying
  /// string storage object. Therefore, identical strings are guaranteed to
  /// compare equal with `==`, but not all equal strings are considered
  /// identical.
  ///
  /// - Performance: O(1)
  @_alwaysEmitIntoClient
  public func _isIdentical(to other: Self) -> Bool {
    self._guts.rawBits == other._guts.rawBits
  }
}

```

We don’t see this API currently being used in standard library, but it’s possible this API is already being used to optimize performance in private frameworks from Apple.

Many more examples of `isIdentical` functions are currently shipping in `Swift-Collections`\[2\]\[3\]\[4\]\[5\]\[6\]\[7\]\[8\]\[9\]\[10\]\[11\]\[12\]\[13\], `Swift-Markdown`\[14\], and `Swift-CowBox`\[15\]. We also support `isIdentical` on the upcoming `Span` and `RawSpan` types from Standard Library.\[16\]

## Proposed Solution

Many types in Standard Library are “copy-on-write” data structures. These types present as value types, but can leverage a reference to some shared state to optimize for performance. When we copy this value we copy a reference to shared storage. If we perform a mutation on a copy we can preserve value semantics by copying the storage reference to a unique value before we write our mutation: we “copy” on “write”.

This means that many types in Standard Library already have some private reference that can be checked in constant-time to determine if two values are identical. Because these types copy before writing, two values that are identical by their shared storage _must_ be equal by value.

Suppose our `Equatable` protocol adopts a method that can return in constant time if two instances are identical and must be equal by-value. We can now refactor our operation on `AsyncSequence` to:

```swift
func f3<S>(sequence: S) async throws
where S: AsyncSequence, S.Element: Equatable {
  var oldElement: S.Element?
  for try await element in sequence {
    if oldElement?.isKnownIdentical(to: element) ?? false { continue }
    oldElement = element
    doLinearOperation(with: element)
  }
}

```

What has this done for our performance? We know that `doLinearOperation` performs a linear operation over `element`. We also know that `isKnownIdentical` returns in constant-time. If `isKnownIdentical` returns `true` we skip performing `doLinearOperation`. If `isIdentical` returns `false` or `nil` we perform `doLinearOperation`, but this is now _one_ linear operation. We will potentially perform this linear operation _even if_ the `element` returned is equal by-value, but since the preflight check to confirm value equality was _itself_ a linear operation, we now perform one linear operation instead of two.

## Detailed Design

Here is a new method defined on `Equatable`:

```swift
public protocol Equatable {
  // The original requirement is unchanged.
  static func == (lhs: Self, rhs: Self) -> Bool
  
  // Returns if `self` can be quickly determined to be identical to `other`.
  //
  // - A `nil` result indicates that the type does not implement a fast test for
  // this condition, and that it only provides the full `==` implementation.
  // - A `true` result indicates that the two values are definitely identical
  // (for example, they might share their hidden reference to the same
  // storage representation). By reflexivity, `==` is guaranteed to return
  // `true` in this case.
  // - A `false` result indicates that the two values aren't identical. Their
  // contents may or may not still compare equal in this case.
  //
  // Complexity: O(1).
  @available(SwiftStdlib 6.3, *)
  func isKnownIdentical(to other: Self) -> Bool?
}

@available(SwiftStdlib 6.3, *)
extension Equatable {
  @available(SwiftStdlib 6.3, *)
  func isKnownIdentical(to other: Self) -> Bool? { nil }
}

```

We add `isKnownIdentical` to _all_ types that adopt `Equatable`, but types that adopt `Equatable` choose to “opt-in” with their own custom implementation of `isKnownIdentical`. By default, all types return `nil` to indicate this type does not have the ability to make any decision about identity equality.

If a type _does_ have some ability to quickly test for identity equality, this type can return `true` or `false` from `isKnownIdentical`. Here is an example from `String`:

```swift
extension String {
  func isKnownIdentical(to other: Self) -> Bool? {
    self._isIdentical(to: other)
  }
}

```

Here is an example of a copy-on-write data structure that manages some private `storage` property for structural sharing:

```swift
extension CowBox {
  func isKnownIdentical(to other: Self) -> Bool? {
    self._storage === other._storage
  }
}

```

## Source Compatibility

Adding a new requirement to an existing protocol is source breaking if that new requirement uses `Self` _and_ that new requirement is the _first_ use of `Self`. Because our existing `==` operator on `Equatable` used `Self`, this proposal is safe for source compatibility.

## Impact on ABI

Adding a new requirement to an existing protocol is ABI breaking if we do not include an unconstrained default implementation. Because we include a default implementation of `isKnownIdentical`, this proposal is safe for ABI compatibility.

## Alternatives Considered

### New `Distinguishable` protocol

The original version of this pitch suggested a new protocol independent of `Equatable`:

```swift
protocol Distinguishable {
  func isKnownIdentical(to other: Self) -> Bool?
}

```

Algorithms from generic contexts that operated on `Distinguishable` could then use `isKnownIdentical` to optimize performance:

```swift
func f4<S>(sequence: S) async throws
where S: AsyncSequence, S.Element: Distinguishable {
  var oldElement: S.Element?
  for try await element in sequence {
    if oldElement?.isKnownIdentical(to: element) ?? false { continue }
    oldElement = element
    doLinearOperation(with: element)
  }
}

```

This is good… but let’s think about what happens if the `element` returned by `sequence` might not _always_ be `Distinguishable`. We can assume the `element` will always be `Equatable`, but we have to “code around” `Distinguishable`:

```swift
func f2<S>(sequence: S) async throws
where S: AsyncSequence, S.Element: Equatable {
  var oldElement: S.Element?
  for try await element in sequence {
    if oldElement == element { continue }
    oldElement = element
    doLinearOperation(with: element)
  }
}

func f4<S>(sequence: S) async throws
where S: AsyncSequence, S.Element: Distinguishable {
  var oldElement: S.Element?
  for try await element in sequence {
    if oldElement?.isKnownIdentical(to: element) ?? false { continue }
    oldElement = element
    doLinearOperation(with: element)
  }
}

func f5<S>(sequence: S) async throws
where S: AsyncSequence, S.Element: Distinguishable, S.Element: Equatable {
  var oldElement: S.Element?
  for try await element in sequence {
    if oldElement?.isKnownIdentical(to: element) ?? false { continue }
    oldElement = element
    doLinearOperation(with: element)
  }
}

```

We now need _three_ different specializations:

- One for a type that is `Equatable` and not `Distinguishable`.
- One for a type that is `Distinguishable` and not `Equatable`.
- One for a type that is `Equatable` and `Distinguishable`.

A `Distinguishable` protocol would offer a lot of flexibility: product engineers could define types (such as `Span` and `RawSpan`) that have the ability to return a meaningful answer to `isKnownIdentical` without adopting `Equatable`. The trouble is that the price we pay for that extra flexibility is much more extra ceremony to support a new generic context specialization when we expect most engineers want to use `isKnownIdentical` in place of value equality.

### Overload for `===`

Could we “overload” the `===` operator from `AnyObject`? This proposal considers that question to be orthogonal to our goal of exposing identity equality with the `isKnownIdentical` method. We could choose to overload `===`, but this would be a larger “conceptual” and “philosophical” change because the `===` operator is currently meant for `AnyObject` types — not value types like `String` and `Array`.

### Overload for Optionals

When working with `Optional` values we can add the following overload:

```swift
@available(SwiftStdlib 6.3, *)
extension Optional {
  @available(SwiftStdlib 6.3, *)
  public func isKnownIdentical(to other: Self) -> Bool?
  where Wrapped: Equatable {
    switch (self, other) {
    case let (value?, other?):
      return value.isKnownIdentical(to: other)
    case (nil, nil):
      return true
    default:
      return false
    }
  }
}

```

Because this overload needs no `private` or `internal` symbols from Standard Library, we can omit this overload from our proposal. Product engineers that want this overload can choose to implement it for themselves.

### Alternative Semantics

Instead of publishing an `isKnownIdentical` function which implies two types _must_ be equal, could we think of things from the opposite direction? Could we publish a `maybeDifferent` function which implies two types _might not_ be equal? This then introduces some potential ambiguity for product engineers: to what extent does “maybe different” imply “probably different”? This ambiguity could be settled with extra documentation on the protocol, but `isKnownIdentical` solves that ambiguity up-front. The `isKnownIdentical` function is also consistent with the prior art in this space.

In the same way this proposal exposes a way to quickly check if two `Equatable` values _must_ be equal, product engineers might want a way to quickly check if two `Equatable` values _must not_ be equal. This is an interesting idea, but this can exist as an independent proposal. We don’t need to block the review of this proposal on a review of `isKnownNotIdentical` semantics.

## Acknowledgments

Thanks [@dnadoba](https://forums.swift.org/u/dnadoba) for suggesting the `isKnownIdentical` function should exist on a protocol.

Thanks [@Ben\_Cohen](https://forums.swift.org/u/Ben_Cohen) for helping to think through and generalize the original use-case and problem-statement.

Thanks [@Slava\_Pestov](https://forums.swift.org/u/Slava_Pestov) for helping to investigate source-compatibility and ABI implications of a new requirement on an existing protocol.

* * *

1. [swift/stdlib/public/core/String.swift at swift-6.1-RELEASE · swiftlang/swift · GitHub](https://github.com/swiftlang/swift/blob/swift-6.1-RELEASE/stdlib/public/core/String.swift#L397-L415) 

2. [swift-collections/Sources/DequeModule/Deque.\_Storage.swift at 1.2.0 · apple/swift-collections · GitHub](https://github.com/apple/swift-collections/blob/1.2.0/Sources/DequeModule/Deque._Storage.swift#L223-L225) 

3. [swift-collections/Sources/HashTreeCollections/HashNode/\_HashNode.swift at 1.2.0 · apple/swift-collections · GitHub](https://github.com/apple/swift-collections/blob/1.2.0/Sources/HashTreeCollections/HashNode/_HashNode.swift#L78-L80) 

4. [swift-collections/Sources/HashTreeCollections/HashNode/\_RawHashNode.swift at 1.2.0 · apple/swift-collections · GitHub](https://github.com/apple/swift-collections/blob/1.2.0/Sources/HashTreeCollections/HashNode/_RawHashNode.swift#L50-L52) 

5. [swift-collections/Sources/RopeModule/BigString/Conformances/BigString+Equatable.swift at 1.2.0 · apple/swift-collections · GitHub](https://github.com/apple/swift-collections/blob/1.2.0/Sources/RopeModule/BigString/Conformances/BigString%2BEquatable.swift#L14-L16) 

6. [swift-collections/Sources/RopeModule/BigString/Views/BigString+UnicodeScalarView.swift at 1.2.0 · apple/swift-collections · GitHub](https://github.com/apple/swift-collections/blob/1.2.0/Sources/RopeModule/BigString/Views/BigString%2BUnicodeScalarView.swift#L77-L79) 

7. [swift-collections/Sources/RopeModule/BigString/Views/BigString+UTF8View.swift at 1.2.0 · apple/swift-collections · GitHub](https://github.com/apple/swift-collections/blob/1.2.0/Sources/RopeModule/BigString/Views/BigString%2BUTF8View.swift#L39-L41) 

8. [swift-collections/Sources/RopeModule/BigString/Views/BigString+UTF16View.swift at 1.2.0 · apple/swift-collections · GitHub](https://github.com/apple/swift-collections/blob/1.2.0/Sources/RopeModule/BigString/Views/BigString%2BUTF16View.swift#L39-L41) 

9. [swift-collections/Sources/RopeModule/BigString/Views/BigSubstring.swift at 1.2.0 · apple/swift-collections · GitHub](https://github.com/apple/swift-collections/blob/1.2.0/Sources/RopeModule/BigString/Views/BigSubstring.swift#L100-L103) 

10. [swift-collections/Sources/RopeModule/BigString/Views/BigSubstring+UnicodeScalarView.swift at 1.2.0 · apple/swift-collections · GitHub](https://github.com/apple/swift-collections/blob/1.2.0/Sources/RopeModule/BigString/Views/BigSubstring%2BUnicodeScalarView.swift#L94-L97) 

11. [swift-collections/Sources/RopeModule/BigString/Views/BigSubstring+UTF8View.swift at 1.2.0 · apple/swift-collections · GitHub](https://github.com/apple/swift-collections/blob/1.2.0/Sources/RopeModule/BigString/Views/BigSubstring%2BUTF8View.swift#L64-L67) 

12. [swift-collections/Sources/RopeModule/BigString/Views/BigSubstring+UTF16View.swift at 1.2.0 · apple/swift-collections · GitHub](https://github.com/apple/swift-collections/blob/1.2.0/Sources/RopeModule/BigString/Views/BigSubstring%2BUTF16View.swift#L87-L90) 

13. [swift-collections/Sources/RopeModule/Rope/Basics/Rope.swift at 1.2.0 · apple/swift-collections · GitHub](https://github.com/apple/swift-collections/blob/1.2.0/Sources/RopeModule/Rope/Basics/Rope.swift#L68-L70) 

14. [swift-markdown/Sources/Markdown/Base/Markup.swift at swift-6.1.1-RELEASE · swiftlang/swift-markdown · GitHub](https://github.com/swiftlang/swift-markdown/blob/swift-6.1.1-RELEASE/Sources/Markdown/Base/Markup.swift#L370-L372) 

15. [Swift-CowBox/Sources/CowBox/CowBox.swift at 1.1.0 · Swift-CowBox/Swift-CowBox · GitHub](https://github.com/Swift-CowBox/Swift-CowBox/blob/1.1.0/Sources/CowBox/CowBox.swift#L19-L27) 

16. [swift-evolution/proposals/0447-span-access-shared-contiguous-storage.md at main · swiftlang/swift-evolution · GitHub](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0447-span-access-shared-contiguous-storage.md)

---

<div class="post-metadata">

**Author:** ![Joe\_Groff](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/joe_groff/32/1929_2.png) [@Joe\_Groff](https://forums.swift.org/u/Joe_Groff)\
**Post date:** [June 16, 2025, 6:45pm UTC](https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497/2 "2025-06-16T18:45:22Z")

</div>

How many different implementations of `isKnownIdentical` do we think there can realistically be? There is a universal implementation that works for all native `Copyable` Swift types, which is to `memcmp` the contents of two values of the same type. One possible refinement to that implementation might be to also mask out insignificant bits and padding bytes, but that could potentially be done by deriving the padding bytes from type metadata like SwiftUI does. Having this as a concrete implementation instead of a protocol requirement would mean that it can be used efficiently in generic contexts and in bulk over arrays of values without having to make an indirect call to a protocol implementation for every element.

---

<div class="post-metadata">

**Author:** ![grynspan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/grynspan/32/15315_2.png) [@grynspan](https://forums.swift.org/u/grynspan)\
**Post date:** [June 16, 2025, 6:51pm UTC](https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497/3 "2025-06-16T18:51:41Z")

</div>

> [@Joe\_Groff](#):
>
> How many different implementations of `isKnownIdentical` do we think there can realistically be? There is a universal implementation that works for all native Swift types, which is to `memcmp` the contents of two values of the same type.

It might be worth having that implementation factored out into a helper function with a relatively type-agnostic signature so that implementations can opt to use it as a one-liner. Perhaps something like:

```swift
func areKnownIdentical<T>(_ lhs: borrowing T, _ rhs: borrowing T) -> Bool where T: ~Copyable & ~Escapable

```

Naming is hard. Still, this isn't something we want folks to reach for by reflex (they should use the protocol member), so we might want to give it a slightly scarier name?

---

<div class="post-metadata">

**Author:** ![FlorianPircher](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/florianpircher/32/39919_2.png) [@FlorianPircher](https://forums.swift.org/u/FlorianPircher)\
**Post date:** [June 16, 2025, 7:05pm UTC](https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497/4 "2025-06-16T19:05:03Z")

</div>

I would favor a function as well as it allows overloading with optional `T` on either side:

> [@\[Pitch\] \`Distinguishable\` protocol for Quick Comparisons](https://forums.swift.org/t/pitch-distinguishable-protocol-for-quick-comparisons/79145/48):
>
> I would prefer to see this implemented as a global function. That way, autocomplete does not get polluted, but developers that want and know about this optimization still have easy access. func areKnownIdentical\<T: KnownIdenticalComparable\>(\_ lhs: T, \_ rhs: T) -\> Bool The main benefit is that this allows working with optionals, where there are overloads to areKnownIdentical with T? on either side. If both values are nil, return true. If only one is nil, return false. If both are non-nil, call …

---

<div class="post-metadata">

**Author:** ![grynspan](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/grynspan/32/15315_2.png) [@grynspan](https://forums.swift.org/u/grynspan)\
**Post date:** [June 16, 2025, 7:05pm UTC](https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497/5 "2025-06-16T19:05:35Z")

</div>

"Great minds" and all. 🙂

---

<div class="post-metadata">

**Author:** ![vanvoorden](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/vanvoorden/32/33619_2.png) [@vanvoorden](https://forums.swift.org/u/vanvoorden)\
**Post date:** [June 16, 2025, 8:04pm UTC](https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497/6 "2025-06-16T20:04:30Z")

</div>

> [@Joe\_Groff](#):
>
> How many different implementations of `isKnownIdentical` do we think there can realistically be?

I have an independent pitch for adding identity equality methods to concrete types from standard library:

- String
- Substring
- Array
- ArraySlice
- ContiguousArray
- Dictionary
- Set

There could be more… but I think these would be the best candidates for a first-pass.

And then there are types from Foundation, Swift-Collections, and any custom types from product engineers that want to expose their own custom idea of identity equality.

> [@Joe\_Groff](#):
>
> There is a universal implementation that works for all native `Copyable` Swift types, which is to `memcmp` the contents of two values of the same type.

For the most part I think this can get us _most_ of the way there… but I also believe there might be situations that we would need more code to defend against.

There are two important goals we want for a method to determine identity equality:

1. Returns `true` to imply values _must_ be equal by value.
2. Returns in constant-time _without_ a linear-time check for value equality.

~~Let's take a closer look at number one and see what might hurt us with `memcmp`. Here is an example of an `Element` that we might want to check for identity equality using `memcmp`:~~

```swift
final class Storage {
  var x = 0
  var y = 0
}

struct Element: Equatable {
  private let storage = Storage()
  
  static func == (lhs: Element, rhs: Element) -> Bool {
    lhs.storage.x == rhs.storage.x &&
    lhs.storage.y == rhs.storage.y
  }
}

```

~~And here is where we might receive these `Element` values:~~

```swift
func isKnownIdentical<T>(_ lhs: T, _ rhs: T) -> Bool {
  // TODO: memcmp
}

func f4<S>(sequence: S) async throws
where S: AsyncSequence, S.Element == Element {
  var oldElement: S.Element?
  for try await element in sequence {
    if isKnownIdentical(oldElement, element) { continue }
    oldElement = element
    doLinearOperation(with: element)
  }
}

```

~~Keep in mind our `sequence` is _asynchronous_ and we receive these `Element` values over time. Because our `Storage` makes no guarantees of immutability… we could receive an `Element` value at time `T(1)` that compares as "identical" to an `Element` value at time `T(0)`… but these two values _do not_ compare equal by value: the underlying `Storage` has mutated underneath us. The `memcmp` did what it was supposed to: it compared the bytes of `Element` and returned `true` when those bytes were equal. But we lost our important goal number one: returning `true` for identity equality implies these instances _must_ return `true` for value equality.~~

Actually… nevermind… that wasn't a good example.

Let's take a closer look at number two and see what might hurt us with `memcmp`. Here is an example of another `Element`:\[1\]

```swift
struct Element: Equatable {
  // A struct with about 80 bytes
  let a: Int64 = 0
  let b: Int64 = 0
  let c: Int64 = 0
  let d: Int64 = 0
  let e: Int64 = 0
  let f: Int64 = 0
  let g: Int64 = 0
  let h: Int64 = 0
  let i: Int64 = 0
  let j: Int64 = 0
}

```

The cost of a check for value equality is 80 bytes. The cost of a check for identity equality using `memcmp` is… also 80 bytes. At this point we have lost our important goal number two: we return from our identity equality check in constant time _without_ a linear time check for value equality. If this `Element` was built on top of some kind of copy-on-write storage then we can assume identity equality would be equal to the cost of checking just one pointer: 8 bytes on a 64 bit architecture.

> [@Joe\_Groff](#):
>
> Having this as a concrete implementation instead of a protocol requirement would mean that it can be used efficiently in generic contexts and in bulk over arrays of values without having to make an indirect call to a protocol implementation for every element.

I think the question of whether or not identity equality ships as a method on `Equatable` or as a "free" function is important and I do look forward to discussing pros and cons. But if we _did_ implement a free function… my opinion right this moment is we don't actually want `memcmp` as a default. What we want as a default is `nil`:

```swift
func isKnownIdentical<T>(_ lhs: T, _ rhs: T) -> Bool? {
  nil
}

```

The `nil` here is a signal to the product engineer that this specific type has no ability to determine a concept of identity equality.

And then library maintainers can override this with a concrete implementation on types that can return some meaningful answer for identity equality:

```swift
func isKnownIdentical(_ lhs: String, _ rhs: String) -> Bool? {
  lhs._isIdentical(to: rhs)
}

```

I think this should work as an alternative to a method on `Equatable`… the compiler should choose for us the correct override at compile time AFAIK.

* * *

1. [Swift’s Copy-on-write Optimisation | Jared Khan](https://jaredkhan.com/blog/swift-copy-on-write)

---

<div class="post-metadata">

**Author:** ![vanvoorden](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/vanvoorden/32/33619_2.png) [@vanvoorden](https://forums.swift.org/u/vanvoorden)\
**Post date:** [June 16, 2025, 11:15pm UTC](https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497/7 "2025-06-16T23:15:26Z")

</div>

> [@FlorianPircher](#):
>
> I would favor a function as well as it allows overloading with optional `T` on either side:

Could that not be supported on a method with the snippet from the pitch?

```swift
@available(SwiftStdlib 6.3, *)
extension Optional {
  @available(SwiftStdlib 6.3, *)
  public func isKnownIdentical(to other: Self) -> Bool?
  where Wrapped: Equatable {
    switch (self, other) {
    case let (value?, other?):
      return value.isKnownIdentical(to: other)
    case (nil, nil):
      return true
    default:
      return false
    }
  }
}

```

---

<div class="post-metadata">

**Author:** ![xwu](https://avatars.discourse-cdn.com/v4/letter/x/b487fb/32.png) [@xwu](https://forums.swift.org/u/xwu)\
**Post date:** [June 17, 2025, 12:18am UTC](https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497/8 "2025-06-17T00:18:49Z")

</div>

> [@vanvoorden](#):
>
> There are two important goals we want for a method to determine identity equality:
> 
> 1. Returns `true` to imply values _must_ be equal by value.
> 2. Returns in constant-time _without_ a linear-time check for value equality.

If the goal is to expose a first-pass "fast" operation, this would be already utterable in Swift 6.2 on concrete types (modulo any optimization bugs) as `span.isIdentical(to: other.span)`.

I think there's an argument to be made that noncopyable types ought to have `===` just like class types; if we were to accept that argument (not mandatory), the idiomatic spelling for this operation on any "Spannable" type could then be `span === other.span`.

We don't have the protocol hierarchy to identify "Spannable" types yet, but that seems like it will (or can, if we keep it in mind) fall out of the inevitable work ahead of us of creating a container hierarchy that accommodates noncopyable types.

I think this all composes very nicely and spares us the need for additional dedicated protocol requirements or APIs, or to introduce a named concept of "identity equality" to copyable types in an already overloaded (ha) space which has `==`, `===`, `Identifiable`, etc.

---

<div class="post-metadata">

**Author:** ![FlorianPircher](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/florianpircher/32/39919_2.png) [@FlorianPircher](https://forums.swift.org/u/FlorianPircher)\
**Post date:** [June 17, 2025, 6:41am UTC](https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497/9 "2025-06-17T06:41:24Z")

</div>

> [@vanvoorden](#):
>
> Could that not be supported on a method with the snippet from the pitch?

I feel uneasy about adding methods to `Optional`. Optionals are mostly interacted with using overloads, operators, and syntax sugar in Swift. Correctly, every time I use `map` on an `Optional` feels like I am making the code more difficult to read for future me.

For example, an `Int` does not have a `map` method, so if I read something like `counter.map { $0 + set.count }` I get that `counter` is actually an `Int?`. But `String`, `Array`, etc. also have `map` methods and now when I am bug hunting I am reading such code much more slowly, checking if `(…).map { … }` should have been `(…)?.map { … }`.

`isKnownIdentical` falls even more so into this trap since every optional type for which `(…).isKnownIdentical(to: …)` is valid code, so too is `(…)?.isKnownIdentical(to: …)`.

The later case (`(…)?.isKnownIdentical(to: …)`) may also be typed accidentally. This returns `nil` if the `lhs` is `nil`, even when the `rhs` might also be `nil` and thus the return value should be `true`. A freestanding function doesn’t suffer from this confusing call site.

> [@xwu](#):
>
> If the goal is to expose a first-pass "fast" operation, this would be already utterable in Swift 6.2 on concrete types (modulo any optimization bugs) as `span.isIdentical(to: other.span)`.

If I understand `Span` correctly, this only works for contiguous memory, not necessarily a `Dictionary` or some tree structure which cannot provide a span view.

---

<div class="post-metadata">

**Author:** ![vanvoorden](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/vanvoorden/32/33619_2.png) [@vanvoorden](https://forums.swift.org/u/vanvoorden)\
**Post date:** [June 17, 2025, 6:29pm UTC](https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497/10 "2025-06-17T18:29:09Z")

</div>

> [@xwu](#):
>
> We don't have the protocol hierarchy to identify "Spannable" types yet, but that seems like it will (or can, if we keep it in mind) fall out of the inevitable work ahead of us of creating a container hierarchy that accommodates noncopyable types.
> 
> I think this all composes very nicely and spares us the need for additional dedicated protocol requirements or APIs, or to introduce a named concept of "identity equality" to copyable types in an already overloaded (ha) space which has `==`, `===`, `Identifiable`, etc.

If what you are suggesting is that checking for identity equality can exist _independently_ of the `Equatable` protocol this was part of the original pitch and is currently an "Alternative Considered". One reason we kept this inside `Equatable` is to prevent against needing extra generic specialization overloads. Where a product engineer needs:

- One generic specialization for a type that is `Equatable` and is `Spannable`.
- One generic specialization for a type that is `Equatable` and _is not_ `Spannable`.
- One generic specialization for a type that _is not_ `Equatable` and is `Spannable`.

Since we expect product engineers want `isKnownIdentical` in-place of (or accompanying) the result of a `==` value operator we think keeping that in `Equatable` is the better trade off for now.

---

<div class="post-metadata">

**Author:** ![vanvoorden](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/vanvoorden/32/33619_2.png) [@vanvoorden](https://forums.swift.org/u/vanvoorden)\
**Post date:** [June 17, 2025, 6:34pm UTC](https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497/11 "2025-06-17T18:34:05Z")

</div>

> [@grynspan](#):
>
> It might be worth having that implementation factored out into a helper function with a relatively type-agnostic signature so that implementations can opt to use it as a one-liner. Perhaps something like:
> 
> ```swift
> func areKnownIdentical<T>(_ lhs: borrowing T, _ rhs: borrowing T) -> Bool where T: ~Copyable & ~Escapable
> 
> ```
> 
> Naming is hard. Still, this isn't something we want folks to reach for by reflex (they should use the protocol member), so we might want to give it a slightly scarier name?

Just to help me understand the feedback on that… are you suggesting that the pitch could be refined to expose a `public` and official-slash-supported "free" function _in addition_ to our idea that a member method could be added to either an existing protocol like `Equatable` or a new protocol? I'm not opposed to this idea right this moment and would like to think it through… but I also wanted to understand what direction you were thinking about that. Thanks!

---

<div class="post-metadata">

**Author:** ![vanvoorden](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/vanvoorden/32/33619_2.png) [@vanvoorden](https://forums.swift.org/u/vanvoorden)\
**Post date:** [June 17, 2025, 6:56pm UTC](https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497/12 "2025-06-17T18:56:07Z")

</div>

> [@FlorianPircher](#):
>
> I feel uneasy about adding methods to `Optional`. Optionals are mostly interacted with using overloads, operators, and syntax sugar in Swift. Correctly, every time I use `map` on an `Optional` feels like I am making the code more difficult to read for future me.

Hmm… what would your thoughts be about a `static` member method on `Equatable` as an alternative to an instance method?

```swift
protocol Equatable {
  static func isKnownIdentical(lhs: Self, rhs: Self) -> Bool?
}

extension Equatable {
  static func isKnownIdentical(lhs: Self, rhs: Self) -> Bool? { nil }
}

extension String {
  static func isKnownIdentical(lhs: Self, rhs: Self) -> Bool? {
    lhs._isIdentical(to: rhs)
  }
}

@main
struct MyExecutable {
  static func main() {
    let s = "Hello, world!"
    print(String.isKnownIdentical(lhs: s, rhs: s))
  }
}

```

Could you please help me understand if this could give us a better way of handling optional values?

---

<div class="post-metadata">

**Author:** ![FlorianPircher](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/florianpircher/32/39919_2.png) [@FlorianPircher](https://forums.swift.org/u/FlorianPircher)\
**Post date:** [June 17, 2025, 7:14pm UTC](https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497/13 "2025-06-17T19:14:59Z")

</div>

I prefer this over the method, but it’s also redundant as the type is already specified by the parameters. So, instead of

```swift
if String.isKnownIdentical(lhs: s, rhs: s) { … }

```

I would spell it

```swift
if isKnownIdentical(s, s) { … }

```

similar to how `==` is defined and called without invoking the type explicitly.

---

<div class="post-metadata">

**Author:** ![vanvoorden](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/vanvoorden/32/33619_2.png) [@vanvoorden](https://forums.swift.org/u/vanvoorden)\
**Post date:** [June 17, 2025, 7:26pm UTC](https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497/14 "2025-06-17T19:26:09Z")

</div>

> [@FlorianPircher](#):
>
> I would spell it
> 
> ```swift
> if isKnownIdentical(s, s) { … }
> 
> ```
> 
> similar to how `==` is defined and called without invoking the type explicitly.

Hmm… for some reason this fails to compile from 6.2:

```swift
protocol Equatable {
  static func isKnownIdentical(_ lhs: Self, _ rhs: Self) -> Bool?
}

extension Equatable {
  static func isKnownIdentical(_ lhs: Self, _ rhs: Self) -> Bool? { nil }
}

extension String {
  static func isKnownIdentical(_ lhs: Self, _ rhs: Self) -> Bool? {
    lhs._isIdentical(to: rhs)
  }
}

@main
struct MyExecutable {
  static func main() {
    let s = "Hello, world!"
    if isKnownIdentical(s, s) ?? false {
// ^ error: Cannot find 'isKnownIdentical' in scope
      print("true")
    }
  }
}

```

---

<div class="post-metadata">

**Author:** ![FlorianPircher](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/florianpircher/32/39919_2.png) [@FlorianPircher](https://forums.swift.org/u/FlorianPircher)\
**Post date:** [June 17, 2025, 8:24pm UTC](https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497/15 "2025-06-17T20:24:35Z")

</div>

Here is a demo setup. I introduce a new protocol `DemoEquatable` to simulate `Equatable` but with an added requirement:

```swift
// simulation of `Equatable` but with `areKnownIdentical` as requirement
protocol DemoEquatable: Equatable {
	static func areKnownIdentical(_ lhs: Self, _ rhs: Self) -> Bool?
}

extension DemoEquatable {
	static func areKnownIdentical(_ lhs: Self, _ rhs: Self) -> Bool? { nil }
}

// have String and Int partake in simulation of future `Equatable`
extension String: DemoEquatable {
	static func areKnownIdentical(_ lhs: Self, _ rhs: Self) -> Bool? {
		lhs._isIdentical(to: rhs)
	}
}

extension Int: DemoEquatable {}

// freestanding functions
func areKnownIdentical<T: DemoEquatable>(_ lhs: T, _ rhs: T) -> Bool? {
	T.areKnownIdentical(lhs, rhs)
}

func areKnownIdentical<T: DemoEquatable>(_ lhs: T?, _ rhs: T?) -> Bool? {
	switch (lhs, rhs) {
	case (nil, nil):
		return true
	case (let lhs?, let rhs?):
		return T.areKnownIdentical(lhs, rhs)
	default:
		return false
	}
}

// test
let s1 = "abc"
let s2 = "xyz"
let s3: String? = nil

print("String:")
print(areKnownIdentical(s1, s1))
print(areKnownIdentical(s1, nil))
print(areKnownIdentical(nil, s1))
print(areKnownIdentical(s3, s3))
print(areKnownIdentical(s1, s2))

let i1 = 5
let i2 = 9
let i3: Int? = nil

print("\nInt:")
print(areKnownIdentical(i1, i1))
print(areKnownIdentical(i1, nil))
print(areKnownIdentical(nil, i1))
print(areKnownIdentical(i3, i3))
print(areKnownIdentical(i1, i2))

```

The code above prints:

```plaintext
String:
Optional(true)
Optional(false)
Optional(false)
Optional(true)
Optional(false)

Int:
nil
Optional(false)
Optional(false)
Optional(true)
nil

```

---

<div class="post-metadata">

**Author:** ![vanvoorden](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/vanvoorden/32/33619_2.png) [@vanvoorden](https://forums.swift.org/u/vanvoorden)\
**Post date:** [June 17, 2025, 8:42pm UTC](https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497/16 "2025-06-17T20:42:13Z")

</div>

Hmm… so suppose we _did_ ship a "free" function… but we _also_ ship an instance member method on `Equatable`:

```swift
protocol DemoEquatable: Equatable {
  func isKnownIdentical(to other: Self) -> Bool?
}

extension DemoEquatable {
  func isKnownIdentical(to other: Self) -> Bool? { nil }
}

extension String: DemoEquatable {
  func isKnownIdentical(to other: Self) -> Bool? {
    self._isIdentical(to: other)
  }
}

extension Int: DemoEquatable {}

func areKnownIdentical<T: DemoEquatable>(_ lhs: T, _ rhs: T) -> Bool? {
  lhs.isKnownIdentical(to: rhs)
}

func areKnownIdentical<T: DemoEquatable>(_ lhs: T?, _ rhs: T?) -> Bool? {
  switch (lhs, rhs) {
  case (nil, nil):
    return true
  case (let lhs?, let rhs?):
    return lhs.isKnownIdentical(to: rhs)
  default:
    return false
  }
}

@main
struct MyExecutable {
  static func main() {
    // test
    let s1 = "abc"
    let s2 = "xyz"
    let s3: String? = nil

    print("String:")
    print(areKnownIdentical(s1, s1))
    print(areKnownIdentical(s1, nil))
    print(areKnownIdentical(nil, s1))
    print(areKnownIdentical(s3, s3))
    print(areKnownIdentical(s1, s2))

    let i1 = 5
    let i2 = 9
    let i3: Int? = nil

    print("\nInt:")
    print(areKnownIdentical(i1, i1))
    print(areKnownIdentical(i1, nil))
    print(areKnownIdentical(nil, i1))
    print(areKnownIdentical(i3, i3))
    print(areKnownIdentical(i1, i2))
  }
}

```

And this gives product engineers the option to either call the free function _or_ the instance method to determine identity equality. Would you have any thoughts about that? Would the freedom to choose the free function make you indifferent to whether or not the protocol method was static or instance?

---

<div class="post-metadata">

**Author:** ![FlorianPircher](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/florianpircher/32/39919_2.png) [@FlorianPircher](https://forums.swift.org/u/FlorianPircher)\
**Post date:** [June 17, 2025, 9:04pm UTC](https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497/17 "2025-06-17T21:04:19Z")

</div>

A primary style would serve this feature better, I think, as it’s a more advanced use case and so more confusion to people reading code where two styles of a seldomly used API are in use. My demo also allows accessing the static func on the type directly, but at that point it’s easy to drop the type name, so it’s less of a separate style.

The main objection I have to `lhs.isKnownIdentical(to: rhs)` is that identity checking, like equality checking, should not treat the two sides differently. `a.isKnownIdentical(to: b)` should be the same as `b.isKnownIdentical(to: a)`. And it is. But `a?.isKnownIdentical(to: b)` is not the same as `b?.isKnownIdentical(to: a)` and that is easy to miss.

Another reason against the member method is that it adds one more option to the autocomplete menu. This is more a feature that you use when you know you need it, and less one you should stumble over when viewing the autocomplete menu after typing `.`

---

<div class="post-metadata">

**Author:** ![vanvoorden](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/vanvoorden/32/33619_2.png) [@vanvoorden](https://forums.swift.org/u/vanvoorden)\
**Post date:** [June 17, 2025, 9:12pm UTC](https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497/18 "2025-06-17T21:12:23Z")

</div>

> [@FlorianPircher](#):
>
> The main objection I have to `lhs.isKnownIdentical(to: rhs)` is that identity checking, like equality checking, should not treat the two sides differently. `a.isKnownIdentical(to: b)` should be the same as `b.isKnownIdentical(to: a)`. And it is. But `a?.isKnownIdentical(to: b)` is not the same as `b?.isKnownIdentical(to: a)` and that is easy to miss.

This is a fair point… and FWIW the current pitch also does not propose a version of `isKnownIdentical` that supports optionals. An "alternative considered" is a "first class" override to support Optionals… but it is not part of the "core" pitch because it uses no `private` or `internal` symbols. A product engineer that needed or wanted this override could choose to compile that in their own project.

Did I understand your example correctly? In your example `a` and `b` are both optional?

---

<div class="post-metadata">

**Author:** ![FlorianPircher](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/florianpircher/32/39919_2.png) [@FlorianPircher](https://forums.swift.org/u/FlorianPircher)\
**Post date:** [June 17, 2025, 9:42pm UTC](https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497/19 "2025-06-17T21:42:01Z")

</div>

> [@vanvoorden](#):
>
> Did I understand your example correctly? In your example `a` and `b` are both optional?

No, not necessary. The `.?` after the `lhs` optional is just easy to misuse since the return value is already an optional.

---

<div class="post-metadata">

**Author:** ![allevato](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/allevato/32/385_2.png) [@allevato](https://forums.swift.org/u/allevato)\
**Post date:** [June 17, 2025, 9:46pm UTC](https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497/20 "2025-06-17T21:46:16Z")

</div>

> [@FlorianPircher](#):
>
> The main objection I have to `lhs.isKnownIdentical(to: rhs)` is that identity checking, like equality checking, should not treat the two sides differently. `a.isKnownIdentical(to: b)` should be the same as `b.isKnownIdentical(to: a)`. And it is. But `a?.isKnownIdentical(to: b)` is not the same as `b?.isKnownIdentical(to: a)` and that is easy to miss.

On this note, it's also worth pointing out that the section on [Argument Labels](https://www.swift.org/documentation/api-design-guidelines/#argument-labels) in the _Swift API Design Guidelines_ calls out the situation you're talking about, saying

> - **Omit all labels when arguments can’t be usefully distinguished** , e.g. `min(number1, number2)`, `zip(sequence1, sequence2)`.

While that does seem to focus specifically on the labels, I think there's an unstated implication that an API that doesn't distinguish between two (or more) arguments shouldn't privilege one of them by making it the receiver—and the prior art of functions like `min` and `zip` reinforce that.

[Next page](https://forums.swift.org/t/pitch-2-add-isknownidentical-method-for-quick-comparisons-to-equatable/80497.md?page=2)
