Skip to content

Make SwiftValue hash/equality work the same as SwiftObject #69618

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

Merged
merged 2 commits into from
Nov 7, 2023

Conversation

tbkka
Copy link
Contributor

@tbkka tbkka commented Nov 2, 2023

TL;DR: Update PR #68720 with lessons learned in reviewing #69464

Background:

  • SwiftValue can expose Swift value types (structs/enums) to ObjC by wrapping them in an Obj-C object on the heap

  • SwiftObject is the Obj-C type that Swift class objects all inherit from (when viewed from Obj-C). This allows arbitrary Swift class objects to be passed into Obj-C.

History:

In the process of working through #69464, we found a better way to handle an ObjC request for -hash for a type that is Swift Equatable but not Hashable. This PR updates SwiftValue to use the same approach. The approach considers three cases:

  1. A Hashable type can forward both -hash and -isEqual: to the Swift object.

  2. A type that is neither Equatable nor Hashable can implement -isEqual: as the identity check and -hash as returning the address of the object in memory.

  3. A type is that Equatable but not Hashable is more complex.

In this last case, we can easily forward -isEqual: to the Equatable conformance but ObjC also requires us to always provide a compatible -hash implementation. The only way to do this is to have -hash return a constant, but that is a very bad idea in general, so we're also including a log message whenever we see a request for -hash on a Swift value that is Equatable but not Hashable.
To limit performance problems from the logging itself, we emit the log message only once for each type.

Testing: I copied the fairly extensive SwiftObjectNSObject test suite over as SwiftValueNSObject in order to verify the new behaviors and help guard against future regressions.

Update PR swiftlang#68720 with lessons learned in reviewing swiftlang#69464

Background:

* SwiftValue can expose Swift value types (structs/enums)
  to ObjC by wrapping them in an Obj-C object on the heap

* SwiftObject is the Obj-C type that Swift class objects all
  inherit from (when viewed from Obj-C).  This allows arbitrary
  Swift class objects to be passed into Obj-C.

History:

* PR swiftlang#4124 made Obj-C `-hash` and `-isEqual:` work for SwiftValue for Hashable Swift types

* PR swiftlang#68720 extended SwiftValue to also support Equatable Swift types

* PR swiftlang#69464 added similar support to SwiftObject

In the process of working through swiftlang#69464, we found a better way
to handle an ObjC request for `-hash` for a type that is Swift
Equatable but not Hashable.  This PR updates SwiftValue to use
the same approach.  The approach considers three cases:

1. A Hashable type can forward both `-hash` and `-isEqual:` to
   the Swift object.

2. A type that is neither Equatable nor Hashable can implement
   `-isEqual:` as the identity check and `-hash` as returning
   the address of the object in memory.

3. A type is that Equatable but not Hashable is more complex.

In this last case, we can easily forward `-isEqual:` to the
Equatable conformance but ObjC also requires us to
always provide a compatible `-hash` implementation.
The only way to do this is to have `-hash` return a constant,
but that is a very bad idea in general, so we're also including
a log message whenever we see a request for `-hash` on
a Swift value that is Equatable but not Hashable.
To limit performance problems from the logging itself, we
emit the log message only once for each type.
@tbkka tbkka requested review from a team, mikeash and al45tair as code owners November 2, 2023 18:45
Copy link
Contributor

@al45tair al45tair left a comment

Choose a reason for hiding this comment

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

Seems like a good change. I did wonder briefly whether it should be a fatal error to send -hash to a Swift object that is Equatable but not Hashable, but I think on balance the warning approach makes sense.

@tbkka
Copy link
Contributor Author

tbkka commented Nov 3, 2023

Yeah, @lorentey also suggested that in the discussion for #69464. I opted for the warning approach since this isn't a fundamental safety problem.

@glessard
Copy link
Contributor

glessard commented Nov 3, 2023

@swift-ci please test

This entire suite was copied wholesale from SwiftObjectNSObject.
Some of it may not apply, very little of it has been critically
evaluated.  But it should help avoid unexpected changes in SwiftValue behavior.
@tbkka
Copy link
Contributor Author

tbkka commented Nov 4, 2023

The overly-expansive SwiftValueNSObject test suite had a few cases that aren't really ready. I commented those out.

@tbkka
Copy link
Contributor Author

tbkka commented Nov 4, 2023

@swift-ci Please test

@tbkka
Copy link
Contributor Author

tbkka commented Nov 6, 2023

@swift-ci Please test Windows platform

@tbkka
Copy link
Contributor Author

tbkka commented Nov 6, 2023

@swift-ci Please test Windows

1 similar comment
@tbkka
Copy link
Contributor Author

tbkka commented Nov 7, 2023

@swift-ci Please test Windows

@tbkka tbkka merged commit 7a920cd into swiftlang:main Nov 7, 2023
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.

3 participants