[swift-evolution] [Draft] Change @noreturn to unconstructible return type

Thorsten Seitz tseitz42 at icloud.com
Tue Jun 7 15:46:32 CDT 2016



> Am 07.06.2016 um 20:11 schrieb Damien Sorresso via swift-evolution <swift-evolution at swift.org>:
> 
> On 7 Jun, 2016, at 09:47, Brent Royal-Gordon via swift-evolution <swift-evolution at swift.org> wrote:
>>> I disagree. We are discussing how to annotate a function in some way so that the compiler knows that the code following it will never be executed *and* so a human who reads the declaration knows that it does not return. “Never" is a poor choice for that. Never what? Never return? Never use this function? Never say never again?
>> 
>> "Never return". That's why it's in the return type slot, right after the `->`. If you read it out loud, you'll read "returns Never", which is exactly correct.
> 
> A return type makes a lot of sense linguistically but does not cover all practical cases because you might not be the one deciding what the function's signature is. For example, you might implement a protocol method that is non-optional, but you never expect to be called. The only way to indicate that to the compiler is with an attribute.
> -damien

That would be lying to the type system like Java did in their collection library throwing exceptions for some method implementations which is horribly broken.
If you conform to a protocol that means you sign a contract that all the methods of the protocol may be called. There is no way out. 
Except in cases with type parameters (or associated types in protocols) where you might use Never for such a type parameter, thereby making all methods taking arguments of this type uncallable without cheating the type system, e.g.

// quick and dirty example without method bodies and not to be taken too seriously

protocol QueueType {
    associatedtype In
    associatedtype Out
    func enqueue(element: In)
    func dequeue() -> Out
}

struct Queue<In, Out> : QueueType {
    func enqueue(element: In)
    func dequeue() -> Out
}

struct Source<Out> : QueueType {
    func enqueue(element: Never)
    func dequeue() -> Out
}

struct Sink<In> : QueueType {
    func enqueue(element: In)
    func dequeue() -> Never
}

let source: Source<Int> = ...
let sink: Sink<String> = ...
let queue: Queue<Int, String> = ...
queue.enqueue(source.dequeue())
sink.enqueue(queue.dequeue())
source.enqueue(1) // type error

-Thorsten 





> 
>> NoReturn, on the other hand, does *not* read well in that slot: "returns NoReturn". Huh? I mean, I suppose you won't misunderstand it, but it makes no sense whatsoever *as a type name*.
>> 
>>> If you want bottom types for other uses, give them their own appropriate and self documenting names.
>> 
>> The problem is, types flow through the type system. Use a NoReturn method with optional chaining, now you have an Optional<NoReturn>. flatMap over that Optional<NoReturn>, now you have a parameter of type NoReturn. What's a *parameter* of type NoReturn? You'd want it to be, say, a different bottom type named NoPass, but you can't—the type came from a NoReturn, and it's stuck being a NoReturn.
>> 
>> Never works pretty well—honestly, surprisingly well—in all of these contexts. The method returns Never, so optional chaining gives you an Optional<Never>, so flatMap has a Never parameter. I have yet to discover a case where it isn't easily interpreted to mean exactly what it really does mean.
>> 
>> -- 
>> Brent Royal-Gordon
>> Architechies
>> 
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org
>> https://lists.swift.org/mailman/listinfo/swift-evolution
> 
> _______________________________________________
> 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