> 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