> 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