I've been experimenting with making
Never something closer to a true bottom type over the last few days, and wanted to start a discussion around some of the design decisions that have come up. Most of this post is inspired by some of the past discussions of
- [Pitch] Never as a bottom type
- SE-0215 - Conform Never to Equatable and Hashable
- SE-0217 - The "Unwrap or Die" operator
The general consensus from past discussions seems to be:
- It's generally useful to be able to treat uninhabited types as a bottom type in expressions, despite the fact that it could confuse beginners
- It's unclear whether an uninhabited type should be capable of conforming to protocols with static or initializer requirements.
Currently,(edit: this isn't true in all cases). It is probably not desirable for
B <: Aimplies
B.Type <: A.Typein Swift
Never.Typeto be a subtype of all meta types. Instead, as has been noted in past threads,
Neverwould be a subtype of all metatypes because it is a subtype of all types, and
Never.Typeshould have no special subtyping behavior.
Based on the above, I'd like to propose the following:
- All uninhabited types (including
Never) should be convertible to any other type. This satisfies expression use cases like
let x = optional ?? fatalError("optional was nil!"). It also allows us to remove the special case
()->Tconversion which is allowed in single expression function and closure bodies. I've been hacking on an initial implementation of this which seems promising so far. Notably, conversion is weaker than subtyping. For example, uninhabited types could not be used as covariant return types of method overrides ().
- All inhabited types should conform to any protocol which does not have static or initializer requirements(maybe except for static/init requirements w/
Selfparams). I haven't investigated this as thoroughly so far, but with these limitations I believe it can be accomplished by taking advantage of some of the Sema changes to support tuple conformances.
- Don't introduce any special behavior for metatypes of uninhabited types
- Special case only
Neverinstead of all uninhabited types, or add some kind of
@bottomTypeannotation. In my opinion this just adds unnecessary special case behavior.
- Allow uninhabited types to conform to protocols with static/init requirements and synthesize trapping implementations. This potentially adds a lot of runtime complexity for very little gain. It does mean uninhabited types are not true bottom types, but there are few practical benefits.
- Try to establish a 'real' subtyping relation instead of just an implicit conversion. This doesn't seem to have many practical benefits, and it makes the metatype situation potentially more complicated.
- Allow use of
Never-returning expression, for example,
let x = optional ?? throw MyError()this is fairly straightforward to implement, but is of limited usefulness without the changes above.
- Also allow usage of
continueas expressions of type
Never. These introduce some additional design challenges due to the use of autoclosures in the standard library.