> The following names were suggested: NoReturn, Bottom, None, Never.
> I would pick None, because it looks like opposite to Any and fits nicely in 
> generic types.

I discussed all of these options and more. The issue I see with None is that it 
could easily be interpreted as Void to those without a C background. (Actually, 
it's probably the most *natural* name for what we call Void.) `func x() -> 
None` reads like it returns nothing. `func x() -> Never` reads like it does not 
return.

> I would prefer the type to be simple, and be implemented as a case-less enum 
> (not a bottom value, as in Haskell).
> 
> None should be a usual enum, with no compiler magic except that functions 
> returning None are equivalent to current @noreturn.

Could you elaborate on this? I think it would be really useful to have a bottom 
type—useful to the point that, within minutes of deciding to think of examples, 
I quickly came up with some really good ones. Why don't you like having a 
bottom type?

> Example 1.
> let x: None?
> // ...
> let y = x!
> 
> It will trap in runtime not because we discover scary bottom thing, as in 
> Haskell, but because x had value Optional.none at that moment and we asserted 
> otherwise.

I'm not sure what you mean by this. There is no "scary bottom thing"; Bottom or 
None or Never or whatever you call it is still an empty type, and the unwrap 
still fails because the value is `.none`, not `.some`. The only difference is 
that you can say something like `let total = basicBooks + fatalError("implement 
pro books counting")` in an expression and it will compile, since 
Bottom/None/Never is a subtype of `basicBooks`'s type—it's simply one that will 
never actually be created.

I wonder if perhaps your experience with Haskell has given you a false 
impression of how this would work in Swift. Haskell is a pervasively lazy 
language. Every operation in Haskell is lazy and you have little control over 
when anything executes. Because of this, `undefined` values can persist for 
long periods of time and spread deep into your code. But Swift is not 
pervasively lazy; it is (relatively) simple and obvious to figure out when a 
given piece of code will run. When you run a Bottom/None/Never-returning 
expression, it does not return. Period. There is no "it does not return six 
files away from where you wrote it".

> We could prove that it is always true in this case, but compiler must be 
> stupid about this.

Why? The compiler flags an error if it can statically prove a trapping overflow 
will occur. Why shouldn't it flag an error if it can statically prove a force 
unwrap will fail?

> Example 2.
> Compiler should allow including None in structures. Error will show up in 
> constructor, when we will not be able to initialize the field.

Well, you can assign the field from a call to something like `fatalError()`, 
but of course that will crash at runtime. (That's true whether we use a bottom 
type or an empty type, by the way.)

> Example 3.
> None in an enum case makes that case never appear in values of such a type. 
> But compiler can not know about that.

Again: Why? If one of the associated values is Bottom/None/Never, how is my 
code improved by the fact that I still need a case for it in a `switch` 
statement? What's the advantage of not being able to eliminate dead code, or 
call out code that will inevitably fail? We already want these things for other 
uses of Bottom/None/Never, like dead code elimination after a precondition 
fails. Why not here?

-- 
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to