On Sun, Aug 15, 2021 at 1:11 PM Jordan LeDoux <jordan.led...@gmail.com>
wrote:

>
> So your intuition is correct. `foo(never $something)` will result in a
> `TypeError` if you try to call it directly. The only way it can be called
> is by being overridden with a wider type, which is why most of the focus is
> around inheritance. Technically, you *could* use it in a function and that
> would make the function uncallable, because any function with a parameter
> of type never is uncallable unless it is overridden and widened.
>
> This is in line with type theory for how bottom types work in other
> languages as well.
>
> My biggest worry about using something besides `never` is that it *is* the
> bottom type already. It's only usable in return types, but within the
> engine it *is* the bottom type. That's what the bottom type in a type
> system generally means: this can't be used and/or the program stops if this
> is used. If we made a bottom type for returns (which we have), and then
> made a *different* bottom type for arguments, we'd be in a situation that
> is unique in programming languages as far as I can tell. I have done a bit
> of research into this as part of the RFC, and I haven't found a single
> language with multiple bottom types. :/
>
> TypeScript, Elm, and PHP have the bottom type `never`. Ceylon, Kotlin, and
> Scala have the bottom type `Nothing`. Rust has the bottom type `!`,
> JavaScript with Closure Compiler annotations has `!Null` (which is intended
> to mean a non-null member of the null type), Julia has `Union{}`, Python
> has `typing.NoReturn`, and Lisp has `NIL`.
>
> None of them (so far) have multiple bottom types for different
> circumstances.
>
> And the meaning of the type isn't *exactly* "any". It's more like "none".
> But the type `string` contains the "none" concept also. You take "none" and
> then you add the parts that make a string type to "none", and what you're
> left with is just the string type. That's why it can be broadened to
> anything, because *all* types contain `never`, just like you can subtract 0
> from any integer.
>
> I have been focusing on the use cases, which are about how this interacts
> with widening and inheritance. But the type itself I would argue is fully
> descriptive where it is defined: that code can never be called due to the
> type on the parameter being never. It must be inherited. If we did
> something like `any`, that would indicate that the intent for inheritance
> more clearly, but think about the code it's actually defined in. If you had
> the following code:
>
> ```
> class A {
>   public function doSomething(any $var): string {
>   }
> }
> ```
>
> Would you expect calling that method to result in a `TypeError`? Because
> that's what *should* happen. The code it is actually written in cannot
> accept `any` type, in fact it can `never` accept a type.
>
> Jordan
>
>
So the `never` just tells the developer "extend/implement me with a type",
that makes sense to me. Having multiple bottom types (and thus most likely
aliases) would probably make it even more confusing, you're right that this
is probably the best course of action 👍

Reply via email to