-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
Unlock Existential Types for All Protocols #1176
Unlock Existential Types for All Protocols #1176
Conversation
Looks great! I think we can pitch it on the forums soon once all suggestions above (plus ones mentioned in forums private messages, like warnings about compositions with conflicting constraints) have been addressed, in order to start collecting any feedback. |
Added a note about how a composition of protocols that share same-name associated types with different implementations will emit a warning per the forums discussion.
Comments on the forums pitch indicated interest in adding a section discussing how standard library existential types could be transformed under this proposal. The section discusses relying on the automatically-generated existential types and adding conformance to the "base" protocol as a special case – similar to error.
Feedback on the forums pitch suggested that the proposal utilize real-world use-cases as examples instead of 'Identifiable'. The use of 'IntegerStridable' is intentional as knowing the concrete 'Stride' type is unnecessary.
You'll need to change the base branch of this pull request to |
Co-authored-by: Anthony Latsis <aqamoss3fan2010@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you guys think? Unless you have been planning to add something, I think we're set up to ask Joe to schedule the SE review after this session.
Sounds good! I’ll have another look at it today (sorry, I had taken a break from compiler/SE contributions but I’m back now) & then I think it should be good to go! |
I had been quite busy too; now, though, I have more free time. So, yes, I think we can request a review or create a pitch thread — I'm not sure if we should first do the latter. |
|
||
The current semantics regarding existential types prevent language users, especially library authors, from inheriting useful protocols due to the high cost of maintaining a type erasure construct. Namely, the high maintenance cost is a result of type erasure containers constituting hard-to-understand boilerplate code that entails thorough testing and a significant effort when expanding the protocol at hand. Furthermore, regular language users are often confused by the current restriction, and often lack the expertise or resources required for creating correct type-erasure contructs. | ||
|
||
## Future Directions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think that we should add a future direction for opening an existential, and then wrapping it into a type-erasure container? For instance, init(_ box: Hashable)
could be added to AnyHashable
. I'm not sure, though, if this addition could be briefly stated in an existing section, or if we'd have to create a new one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's a bullet point for "automatically opening existentials when passed as generic arguments" at the bottom. That would allow the generic initializer of AnyHashable
to accept a Hashable
value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That would require some implementation work; at the same time, users will be left unable to initialize standard-library-provided type erasers with their language-provided protocol counterparts. I'm not sure if this feature should be part of the proposal, because I think it could create a major usability issue, due to the lack of a feature that can be easily added to the standard library.
Sorry, if I've missed some aspect of the proposed feature that already enables this behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, the part about "automatically opening existential values" is a future direction (it was also mentioned as such a couple of times in the forums); we are not proposing or implementing it now.
users will be left unable to initialize standard-library-provided type erasers with their language-provided protocol counterparts.
In case this is still relevant — why is that? Self-conformance does allow you to initialize an AnyProtocol
wrapper with a Protocol
value, among other stuff.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't very clear.
I'm arguing that implementing "self-conforming" existential types would require some implementation work, which is — obviously — not in scope for this proposal.
Yet, the current proposal (without self-conformance) creates serious usability issues — provided that I haven't missed anything — since users will be unable to write something like AnyHashable(1 as Hashable)
.
What I propose we do, is include:
extension AnyHashable {
public init(_ box: Hashable) {
self = _openExistential(box, do: { unboxed in
AnyHashable(unboxed)
})
}
}
Similarly, we could provide such an initializer for AnyCollection
and any other type-erasing, standard-library wrappers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. But AnyCollection is not really an option, because we need to somehow represent the Element type once we get the wrapper back.
Right. This, then, leaves us just with AnyHashable
.
I have mixed feelings about a permanent workaround to a temporary issue, given that users can add the workaround themselves if they happen to need a new Hashable -> AnyHashable conversion in the meantime. You are totally welcome to add it as a future direction though.
I understand your concern. I think whether a workaround will be implemented depends on the timing of the follow-up proposal for automatically opening existentials.
How about the following for a future direction bullet:
Add an
init(_ box: Hashable)
initializer toAnyHashable
to alleviate confusion and aid in usability. This initializer should be treated as a workaround, and removed once automatic opening of existential types becomes available.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds fine, but
...and removed once automatic opening of existential types becomes available.
this would break the ABI (we cannot remove something public
once added).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I meant "deprecated". Then, after a major version of being deprecated, it could be removed — if that's an option. That, of course, entails that init(_ box: Hashable)
be marked @_disfavoredOverload
, in addition to deprecated.
Is this okay?
Add an
init(_ box: Hashable)
initializer toAnyHashable
to alleviate confusion and aid in usability. This initializer should be treated as a workaround, and deprecated once automatic opening of existential types becomes available.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- "should" -> "would"
- "once" -> "if/when"
LGTM.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just changed if/when ... becomes available
to should ... become available
.
I reckon we're fine with two pitch threads and that much discourse 🙂. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks fantastic! I only have some very minor comments!
# Unlock existentials for all protocols | ||
|
||
* Proposal: [SE-NNNN](NNNN-unlock-existential-types-for-all-protocols.md) | ||
* Authors: [Anthony Latsis](https://github.com/AnthonyLatsis), [Filip Sakel](https://github.com/filip-sakel), [Joe Groff](https://github.com/jckarter), [Suyash Srijan](https://github.com/theblixguy) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I appreciate it, but I don't think I really need author credit for this.
This proposal aims to add support for existential types derived from any protocol.
Forums Thread: https://forums.swift.org/t/lifting-the-self-or-associated-type-constraint-on-existentials/18025
Implementation: swiftlang/swift#33767