Skip to content

[ObjectiveC] Selector: Synthesize Equatable and Hashable #20872

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 1 commit into from
Nov 30, 2018

Conversation

lorentey
Copy link
Member

@lorentey lorentey commented Nov 29, 2018

(This PR was originally part of #20685.)

SE-0206 deprecated hashValue as a Hashable requirement, replacing it with hash(into:).

This PR removes the explicit Selector.hashValue implementation, allowing the compiler to provide a (faster) synthesized Hashable implementation, based on hash(into:). For symmetry, it also removes the explicit definition of ==. (The compiler-synthesized pointer comparison is documented to have the same semantics as sel_isEqual.)

@lorentey
Copy link
Member Author

@swift-ci please test

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - dc44cc7bd08b827425fdf3728dcf08d9b52ca585

@jrose-apple
Copy link
Contributor

Faster because it's inlinable, or faster because the compiler-synthesized definition is going to do extra work? Because if we're just concerned about the latter, we could reasonably special-case single-element structs.

@lorentey
Copy link
Member Author

@jrose-apple The compiler-synthesized hash(into:) works by feeding hashValue to the hasher, which spawns a brand new Hasher to calculate a hash value for the opaque pointer. This is about four times more work than simply feeding the pointer bits to the supplied hasher.

The compiler can't really do a better job at synthesizing hash(into:), since there is an explicit hashValue implementation.

(I'm much more concerned about moving the remaining parts of stdlib away from hashValue than any immediate performance benefits.)

@jrose-apple
Copy link
Contributor

If we could still make ABI-breaking changes, removing hashValue would be a better change, right? Just to be clear?

@lorentey
Copy link
Member Author

lorentey commented Nov 29, 2018

Yeah, removing hashValue as a protocol requirement (and converting it into an extension property) would be the ideal end goal.

However, doing that now would be massively source-breaking; we've only introduced hash(into:) in 4.2, and we're not even emitting deprecation warnings for hashValue implementations yet. (That's hopefully coming soon -- see #20685)

Update: Ah, I see what you mean! We could safely remove the hashValue definition from Selector. This wouldn't even be an ABI-breaking change, since the compiler would just generate a functionally equivalent one from hash(into:). We should do that!

@jrose-apple
Copy link
Contributor

The difference is that it won't be inlinable, though.

@lorentey
Copy link
Member Author

Luckily, the current definition isn't inlinable either. (This is probably fine -- it's a non-generic struct.)

@jrose-apple
Copy link
Contributor

Oh, I'm getting your PRs mixed up. :-) All right, great!

@lorentey lorentey force-pushed the deprecate-hashValue-4 branch from dc44cc7 to 33bfa77 Compare November 29, 2018 21:59
@lorentey
Copy link
Member Author

Done!

@swift-ci smoke test

@jrose-apple
Copy link
Contributor

…and then the next step is that you don't need hash(into:) either, because that's the default implementation. :-)

@lorentey
Copy link
Member Author

Hah, you're right! It's so rare we can use Hashable synthesis in the stdlib, my poor brain can't handle it. :-)

@lorentey
Copy link
Member Author

Hm, removing the hash(into:) definition is probably inadvisable unless we do the same to ==. (We should emit a warning in case Hashable is synthesized, but Equatable isn't.)

The equality operator currently calls sel_isEqual(_, _). Is it safe to compare the pointers directly? (If not, then we probably need to rethink hashing...)

@jrose-apple
Copy link
Contributor

It looks like sel_isEqual is documented to be equivalent to ==, so we should be okay.

@lorentey
Copy link
Member Author

OK, I'll take a deep breath and remove both explicit implementations then.

…zed versions

`Selector.==` currently calls `sel_isEqual`, which is documented to be the same as == on the direct pointer values. We can safely replace the explicit implementation with the compiler-generated one.

`Selector.hashValue` is deprecated as a Hashable requirement, and the preferred method to implement is `hash(into:)`. Implementing the proper function improves hashing performance by eliminating nested Hasher sessions.

By removing the previous definition of `hashValue`, we allow the compiler to synthesize the correct `hash(into:)` (and `hashValue`) implementations.
@lorentey lorentey force-pushed the deprecate-hashValue-4 branch from 33bfa77 to 4e2dfb7 Compare November 29, 2018 23:16
@lorentey
Copy link
Member Author

Third time's the charm!

@swift-ci smoke-test

@lorentey
Copy link
Member Author

@swift-ci smoke-test

@lorentey
Copy link
Member Author

@swift-ci please smoke test

@lorentey lorentey changed the title [ObjectiveC] Selector.hash(into:): Add explicit definition [ObjectiveC] Selector: Synthesize Equatable and Hashable Nov 29, 2018
@lorentey lorentey merged commit 26e8966 into swiftlang:master Nov 30, 2018
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