The review of SE-0319: Never as Identifiable, begins now and runs through July 13, 2021.
Reviews are an important part of the Swift evolution process. All review feedback should be either on this forum thread or, if you would like to keep your feedback private, directly to the review manager or direct message in the Swift forums).
What goes into a review of a proposal?
The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift.
When reviewing a proposal, here are some questions to consider:
- What is your evaluation of the proposal?
- Is the problem being addressed significant enough to warrant a change to Swift?
- Does this proposal fit well with the feel and direction of Swift?
- If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
- How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
Thank you for helping improve the Swift programming language and ecosystem.
Tom Doron
Review Manager
14 Likes
Hello, thanks for this proposal.
As the warning notes, the new conformance will be used to satisfy the protocol requirement. This difference shouldn't present an observable difference given that an instance of Never cannot be constructed.
There is a difference if an existing module declares an ID type which is not Never. The proposal, as written, would break such existing code.
IIRC, previous proposals of the same kind did preserve existing conformances instead of replacing them with the one of the standard library. Maybe someone has a better recollection than mine, and could point to such a precedent?
1 Like
I am +1 on this proposal, it is straight-forward.
However, this continues to highlight a significant design point we need to look at: Never should implicitly conform to a bunch of protocols. Having one-off swift evolution proposals for each of them doesn't really make sense, we should have a systematic approach.
-Chris
34 Likes
ktoso
(Konrad 'ktoso' Malawski 🐟🏴☠️)
4
I support this change, no problem 
But I guess I'll ask the elephant in the room question -- why not look into making Never a true bottom type? It always seemed weird to me that Swift lacked a true bottom type and Never seemed like the natural candidate for it.
This does not block the current proposal from being accepted, just wanted to see if there's any thoughts we can share here?
22 Likes
ricketson
(Matt Ricketson)
5
The acceptance rationale for SE-0215 provides some extra info:
Never should become a blessed bottom type in the language. This matches with semantics in other languages and its intended role in Swift.
With respect to the latter, the Core Team discussed what Never being a bottom type actually meant. From that discussion we reached the following conclusions:
- Semantically, as a bottom type, it would mean that
Never should be implicitly convertible to any other type. This composes well in the type system because of the fact that instances of Never cannot be instantiated.
- However, being a bottom type does not imply that
Never should implicitly conform to all protocols. Instead, convenient protocol conformances for Never should be added as deemed useful or necessary.
There are various details to suss out with making Never a bottom type, and thus making it a bottom type would be served by a separate and well-considered proposal . It is the opinion of the Core Team that making Never a bottom type would be separate from it conforming to all protocols, and thus the motivation of this particular proposal and the particular problems it addresses stands on its own.
With respect to protocol conformances, the Core Team felt the language has clearly moved in a direction where explicit protocol conformance is fundamental to the language model. The compiler has grown affordances to make the implementation of protocol conformances easy in many cases (e.g., synthesized implementations of Hashable ) but that the explicit protocol conformance is quite important. Adding rules for implicit protocol conformances — something that has been considered in Swift’s history — ends up adding real complexity to the language and its implementation that can be hard to reason about by a user as well as by the language implementation.
(which is not the say that that's the end of the discussion, but just the latest official statement from the Core Team. Note of course the explicit invitation for a "separate and well-considered proposal" to discuss further)
3 Likes
toph42
(Topher Hickman)
6
Perhaps that approach should start with a list of all protocols in the Swift Standard Library and solicit any objections to conforming Never to each of them?
I remember that remark. It would be helpful to hear a little more detail about this reasoning, which I’m afraid entirely eludes me.
The bottom type is inherently a unique beast; there can be only one. And in my naïveté, it seems to me that this unique special case can and should conform to all protocols:
From the compiler’s point of view, I would assume that since no runtime values ever belong to it, it does not need a witness table or any other kind of runtime support other than a metatype. In type checking, it would form a unique “always true” special case, one that does not require any sort of more general implicit conformance mechanism.
From the language user’s point of view, I’m hard-pressed to think of any logical reason why any protocol would not want Never to conform to it.
I’m sure there’s an excellent rationale here! It just eludes me. As it stands, Chris’s and Konrad’s remarks echo my sentiments exactly:
If making Never a true bottom type, including all protocols, is off the table, then at least this:
…seems like the minimum sensible approach.
2 Likes
The 2 reasons I know of why Never would not semantically conform to a protocol are:
- an infallible initializer or static var of
Self type (would need to fatalError).
- The protocol is 'closed' (internally exhaustive) and the author did not consider
Never conforming.
4 Likes
Ah, and thus var p: P = Never(…) should logically compile, which is…not nice.
And then there’s the problem of conflicting protocol requirements:
protocol P0 { var x: Int { get } }
protocol P1 { var x: String { get } }
// How can Never conform to both?
It seems to me it might be possible to get around both these problems by prohibiting access to all protocol requirements — initializers, static and instance members, everything — via the naked Never type:
func f(p0: P0, never: Never) {
p0.x // allowed
never.x // not allowed, even though Never conforms to P0
}
Hard to shake the feeling there’s a solution lurking around the corner here. However, I do now see how this becomes a rabbit hole, thanks to your comment!
What would the pitfall of this be in practice? The Never type is unoccupied, so e.g. switching on the runtime type of a value can’t ever hit an unexpected non-match:
protocol P { }
struct A: P { }
struct B: P { }
extension Never: P {}
func f(_ p: P) {
switch p {
case is A: print("a")
case is B: print("b")
default: fatalError("unreachable") // This is in fact unreachable, even though Never: P
}
}
Hmm, I suppose one could gum things up by switching on the metatype of a presumed-exhaustive protocol:
func f(_ p: P.Type) { … }
f(Never.self)
Is that the concern? Is there more I’m missing?
That's what I was thinking of in particular. I don't have any ideas of what one would switch on the metatype for, but it works, and making Never conform to such protocols would change the behavior.
1 Like
jayton
(Jens Ayton)
12
What about the disguised Never type? Recall that types can be materialized in any generic function:
protocol DefaultInitializable {
init()
}
func instantiate<T: DefaultInitializable>() -> T {
return T()
}
let n: Never = instantiate()
The same problem applies to all static methods and properties (not just Self-constrained or otherwise “fancy” ones).
One could work around this by fatalErroring, or maybe returning nil for nullable initializers, but this strikes me as unprincipled; depending on your point of view, it’s either turning an error that should be static into a dynamic one, or implicitly adding ad-hoc behaviour to the bottom type.
It would also require the static parts of protocol conformances to actually be synthesized for Never (either up front or through special runtime synthesis), whereas use of Never as a subtype of a concrete type should never incur overhead.
3 Likes
Runni
Running the risk of derailing this proposal, which is not my intent. (+1 from me)
Why don’t we make adding scoped conformance trivial?
1 Like
tomerd
14
This review for SE-0319 has concluded and the proposal was accepted.
Thank you to everyone for the feedback and contributions to this proposal.
1 Like