[swift-evolution] [Pitch] Never as a bottom type

Yuta Koshizawa koher at koherent.org
Sun May 14 22:21:53 CDT 2017


Joe also referred to the following model in a thread about Typed Throws.

    () -> () == () throws Never -> ()
    () throws -> () == () throws Error -> ()

https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170213/032267.html

It means `Never` must be a subtype of `Error`. I think it is an
interesting use case of "Never as bottom type".


2017-05-15 7:27 GMT+09:00 André Videla via swift-evolution
<swift-evolution at swift.org>:
> Hi Swift-Evolution,
>
> At the end of SE-0102
> (https://github.com/apple/swift-evolution/blob/master/proposals/0102-noreturn-bottom-type.md)
> it is mentioned that the Never type could be used as a universal bottom type
> but that is currently not the case.
>
> As of today the Never type is used as a return type of `fatalError` and as
> function which do not return by the virtue of calling `fatalError`.
> This allows for very useful behaviours for example:
>
> let anything: Any = …
>
> switch anything {
> case let view as UIView: …
> case let str as String: …
> default: fatalError("we got an unexpected type")
> }
>
> But it has its limits, most notably, it cannot be used as an expression
>
> let dunno: Int = fatalError("what should I put here?") // cannot convert
> value of type 'Never'
>
> It makes sense because Never is not a bottom type. If it were, this
> statement would be absolutely valid.
>
> Having a bottom type and a value for it has several advantages:
>
> - More informative error messages with forced unwrap:
>
> protocol WonkyAPI {
>     func apiCall() -> Int? //this always return an Int, why is it optional?
> }
>
> func mycode() {
>     let valueFromAPI = apiCall() ?? fatalError("The API used to always
> return a value, but now it does not!")
>> }
>
> It sometimes happen that some part of the code uses an optional but in your
> particular codepath, the optional is always containing a value (for example
> after an assignment).
> As of today, you can write
> guard let value = value else { fatalError("something terrible happened") }
> for the same effect with a more verbose syntax.
>
> - Use as a hole/placeholder during development
> During development it is very likely that you will want to write a piece of
> functionality but be stuck on an intermediate part of the computation.
> Assume we have an identifier `undefined` of type `Never` which would
> represent an impossible value as a bottom type. We would ben able to write:
>
> func transform(point: CGPoint) -> CGPoint {
>     let translation =  Matrix3D(1, 0, 2,
>                                 0, 1, -2,
>                                 0, 0, 1)
>     let rotation: Matrix3D = undefined //what was it? I forgot
>     return (translation * rotation * point.homogenous).toPoint()
> }
>
> We can debate on the right naming for undefined. Haskell uses 'undefined',
> Scala uses `???`. `unimplemented`, `impossible`, `void`are all valid
> contenders.
>
> - Eliminate type annotations for generic covariant types
> As of today this is not valid
>
> struct Person {
>     let name: String
> }
>
> var maybeSomeone = nil
> maybeSomeone = Person(name: "Doug”)
>
> Even though it is clear that maybeSomeone is of type Optional<Person>.
> That is because the compiler cannot guess which type the Optional wraps when
> `maybeSomeone` is declared. But with a bottom type, a naked nil can be
> mapped to `Optional<Never>` until the type inference figures out from the
> context what is the type of Optional. If it cannot because no use or no
> assignment is done, the compiler could emit an “unreachable” warning just
> like it does for
>
> func unreach() {
>     fatalError("stop here")
>     print("not printed”) // warning: will never be executed
> }
>
> Should I write a proposal?
>
> André Videla
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>


More information about the swift-evolution mailing list