[RFC] noreturn type

php.internals

Matthew Brown

5 years ago
Hey, Ondřej Mirtes and I present an RFC for the noreturn type: https://wiki.php.net/rfc/noreturn_type The feature already exists in Hack (the primary inspiration) and is currently supported by our static analysis tools inside docblocks, and we feel there's a good argument for it to be supported by PHP itself. Thanks, Matt & Ondřej

azjezz

5 years ago
Hey Matthew, I have look at the implementation a few days ago, and was patiently waiting for the RFC. a huge +1 from me ( even tho i can't vote ), `noreturn` type would be a great addition to PHP type system. Regards, Saif. ‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐ On Wednesday, March 10, 2021 7:06 PM, Matthew Brown <matthewmatthew@gmail.com> wrote:

Rowan Collins

5 years ago
On 10/03/2021 18:06, Matthew Brown wrote:
> Ondřej Mirtes and I present an RFC for the noreturn type: > https://wiki.php.net/rfc/noreturn_type
Thanks for the proposal, I can certainly think of uses for it. I am however slightly confused by what exactly the implementation checks, and when. Is it actually looking for "exit" and "throw" statements? The text talks about exiting "explicitly or implicitly", but doesn't give any examples of how this works. For instance, is this code valid, and how does PHP know that it's valid? function my_exit(string $reason): noreturn {     exit("$reason\n"); } function canned_exit(): noreturn {    my_exit("The normal reason"); } The other thing I'd like to mention is that PHP's implementation of "void" consists mostly of checking that there is no return statement, so a separate keyword of "noreturn" may well cause confusion. I would personally prefer the name "never" for this reason. Regards,
-- Rowan Tommins [IMSoP]

Matthew Brown

5 years ago
On Wed, 10 Mar 2021 at 13:55, Rowan Tommins <rowan.collins@gmail.com> wrote:
> I am however slightly confused by what exactly the implementation > checks, and when. Is it actually looking for "exit" and "throw" statements? >
No. Any function annotated with `: noreturn` causes the engine to insert a ZEND_VERIFY_NORETURN_TYPE op at the end of the function's operands. If the Zend engine hits that operand — which only happens if a throw/exit *hasn't* been encountered — it emits a TypeError. The other thing I'd like to mention is that PHP's implementation of
> "void" consists mostly of checking that there is no return statement, so > a separate keyword of "noreturn" may well cause confusion. I would > personally prefer the name "never" for this reason. >
If a significant number agree I can add a secondary vote on noreturn vs never, but never introduces more of a BC risk. Best wishes, Matt

Chase Peeler

5 years ago
On Wed, Mar 10, 2021 at 2:22 PM Matthew Brown <matthewmatthew@gmail.com> wrote:
> On Wed, 10 Mar 2021 at 13:55, Rowan Tommins <rowan.collins@gmail.com> > wrote: > > > I am however slightly confused by what exactly the implementation > > checks, and when. Is it actually looking for "exit" and "throw" > statements? > > > > No. Any function annotated with `: noreturn` causes the engine to insert > a ZEND_VERIFY_NORETURN_TYPE op at the end of the function's operands. > > If the Zend engine hits that operand — which only happens if a throw/exit > *hasn't* been encountered — it emits a TypeError. > > The other thing I'd like to mention is that PHP's implementation of > > "void" consists mostly of checking that there is no return statement, so > > a separate keyword of "noreturn" may well cause confusion. I would > > personally prefer the name "never" for this reason. > > > > If a significant number agree I can add a secondary vote on noreturn vs > never, but never introduces more of a BC risk. > >
I think the difference between void and noreturn is pretty clear, but, if never is more clear, perhaps neverreturn would be an option that would be less likely to have BC risks. Just to throw out some additional ideas, why not two possible types: throws and exits? Don't have any strong opinions on that, but figured I'd add it to the discussion.
> Best wishes, > > Matt >
-- Chase Peeler chasepeeler@gmail.com

Rowan Collins

5 years ago
On 10/03/2021 19:21, Matthew Brown wrote:
> If the Zend engine hits that operand — which only happens if a > throw/exit *hasn't* been encountered — it emits a TypeError.
Right, that should probably be spelled out in the RFC. Checking at run-time in that way is consistent with actual return types, but inconsistent with "void", which performs all its checking at compile-time. On that note, the "comparison to void" section could maybe more clearly call out the difference in behaviour, rather than showing the happy path for both. If I understand right: - the "sayHello" function would give an error at runtime if marked "noreturn" - the "redirect" function would run fine if marked "void" - a function containing "return null;" would fail at compile time for both - a function containing "return;" would be OK for "void", but fail at compile time for "noreturn"? Regards,
-- Rowan Tommins [IMSoP]

Peter Stalman

5 years ago
On Wed., Mar. 10, 2021, 11:22 Matthew Brown, <matthewmatthew@gmail.com> wrote:
> If a significant number agree I can add a secondary vote on noreturn vs > never, but never introduces more of a BC risk. >
Hi Matt, I like this RFC, but I'd like to see the RFC cover if any other languages have a similar return type. The definition of `void` is that it has no return value, so I too agree that the keyword `noreturn` is too close in meaning to `void`. I'd also like to throw the word `deadend` or something similar into the ring, to make things a bit clearer. Thanks, Peter

Sebastian Bergmann

5 years ago
Am 11.03.2021 um 07:51 schrieb Peter Stalman:
> I like this RFC, but I'd like to see the RFC cover if any other languages > have a similar return type.
The RFC has a "Prior art in other interpreted languages" section.

Peter Stalman

5 years ago
On Wed., Mar. 10, 2021, 22:59 Sebastian Bergmann, <sebastian@php.net> wrote:
> Am 11.03.2021 um 07:51 schrieb Peter Stalman: > > I like this RFC, but I'd like to see the RFC cover if any other languages > > have a similar return type. > > The RFC has a "Prior art in other interpreted languages" section. >
Oh, my apologies, I missed that section. I admit I (obviously) didn't read the RFC as diligently as I should have. I'd also like to suggest `terminus`, as it seems to fit by definition: "a final point in space or time; an end or extremity" and "a final goal; a finishing point". It might also be less likely to conflict with any existing code. Thanks, Peter

Brent

5 years ago
Hi Peter and internals
> On 11 Mar 2021, at 07:51, Peter Stalman <sarkedev@gmail.com> wrote: > > On Wed., Mar. 10, 2021, 11:22 Matthew Brown, <matthewmatthew@gmail.com> > wrote: > >> If a significant number agree I can add a secondary vote on noreturn vs >> never, but never introduces more of a BC risk. >> > > Hi Matt, > > I like this RFC, but I'd like to see the RFC cover if any other languages > have a similar return type.
What made it clear to me was this: returning nothing (void) isn't the same as not returning (noreturn, eg throw or exit). Having read that somewhere on Twitter made it easier for me to reason about. It's a useful feature in the static analysis world.
> > The definition of `void` is that it has no return value, so I too agree > that the keyword `noreturn` is too close in meaning to `void`. > > I'd also like to throw the word `deadend` or something similar into the > ring, to make things a bit clearer. > > Thanks, > Peter
Kind regards Brent

Alexandru Pătrănescu

5 years ago
Hi Rowan, On Wed, Mar 10, 2021, 20:55 Rowan Tommins <rowan.collins@gmail.com> wrote:
> On 10/03/2021 18:06, Matthew Brown wrote: > > Ondřej Mirtes and I present an RFC for the noreturn type: > > https://wiki.php.net/rfc/noreturn_type > > > Thanks for the proposal, I can certainly think of uses for it.
> The other thing I'd like to mention is that PHP's implementation of > "void" consists mostly of checking that there is no return statement, so > a separate keyword of "noreturn" may well cause confusion. I would > personally prefer the name "never" for this reason. >
I would mostly say that "void" consists of checking that no value is returned as plain `return;` statements are fine. While actually "noreturn" consists of checking that there is no return statement, implicit or explicit. As another distinction I noticed, for "void" the validation can be done completely at compile time but for "noreturn" both compile and run time are necessary right now. Hopefully, static analysis tools like psalm can further understand better and better the runtime execution paths and provide with errors. I was just reading the github committed RFC earlier this morning and I liked it. Regards, Alex

Kamil Tekiela

5 years ago
Hi Matthew, I am concerned with some edge cases. What if a function both returns and throws at the same time? For example: function a():noreturn { return throw new Exception('Boom!'); } or function a():noreturn { try { throw new Exception('Boom!'); } finally { return; } } Also, the message "TypeError: a(): Nothing was expected to be returned" is inaccurate. It should say that the function should terminate instead of returning. It's also not a TypeError if no value is expected. At the moment it sounds like we need to make the function somehow return nothing. If we are to bikeshed about the name then we might also consider other possibilities: None, Nothing, Returnless Regards, Kamil

Matthew Brown

5 years ago
On Wed, 10 Mar 2021 at 16:04, Kamil Tekiela <tekiela246@gmail.com> wrote:
> I am concerned with some edge cases. What if a function both returns and > throws at the same time? For example: > > function a():noreturn { > return throw new Exception('Boom!'); > } > > or > > function a():noreturn { > try { > throw new Exception('Boom!'); > } finally { > return; > } > } >
In both cases those are compile-time errors, since no return is allowed in a function that has the noreturn type. I've added both as tests ( https://github.com/php/php-src/pull/6761/commits/56ae52e84da5c063c28ba7739ac15979e61afc91) but I don't _think_ it's necessary to mention it in the PR given how much of an edge-case it is.
> Also, the message "TypeError: a(): Nothing was expected to be returned" is > inaccurate. It should say that the function should terminate instead of > returning. It's also not a TypeError if no value is expected. At the moment > it sounds like we need to make the function somehow return nothing. >
It's a TypeError because noreturn is a type, but I agree the error message could be improved. Ilija suggested "noreturn function was expected to throw, terminate or run infinitely" and I'd welcome other suggestions.
> If we are to bikeshed about the name then we might also consider other > possibilities: None, Nothing, Returnless >
I'd prefer to stick to noreturn and never, which have plenty of precedent in other languages' type systems.

A.L.E.C

5 years ago
On 10.03.2021 19:06, Matthew Brown wrote:
> Ondřej Mirtes and I present an RFC for the noreturn type: > https://wiki.php.net/rfc/noreturn_type
I don't like that type covariance would be allowed. Why such an exception to the rules?
-- Aleksander Machniak Kolab Groupware Developer [https://kolab.org] Roundcube Webmail Developer [https://roundcube.net] ---------------------------------------------------- PGP: 19359DC1 # Blog: https://kolabian.wordpress.com

Ben Ramsey

5 years ago
> On Mar 10, 2021, at 13:24, Aleksander Machniak <alec@alec.pl> wrote: > > On 10.03.2021 19:06, Matthew Brown wrote: >> Ondřej Mirtes and I present an RFC for the noreturn type: >> https://wiki.php.net/rfc/noreturn_type > > I don't like that type covariance would be allowed. Why such an > exception to the rules?
It’s not an exception. Returns are covariant. Parameters are contravariant. Since `noreturn` is a subtype of all other types, it behaves as expected. I like the proposal, btw! Cheers, Ben

A.L.E.C

5 years ago
On 10.03.2021 20:28, Ben Ramsey wrote:
>> I don't like that type covariance would be allowed. Why such an >> exception to the rules? > > It’s not an exception. Returns are covariant. Parameters are > contravariant. Since `noreturn` is a subtype of all other types, it > behaves as expected.
I see it's a subtype, I don't get why. Wouldn't it be better to be a separate type so return type covariance is not allowed (as it is with void)? Was it a design decision or a side product of the implementation?
-- Aleksander Machniak Kolab Groupware Developer [https://kolab.org] Roundcube Webmail Developer [https://roundcube.net] ---------------------------------------------------- PGP: 19359DC1 # Blog: https://kolabian.wordpress.com

Ilija Tovilo

5 years ago
Hi Aleksander
> I see it's a subtype, I don't get why. Wouldn't it be better to be a > separate type so return type covariance is not allowed (as it is with > void)? Was it a design decision or a side product of the implementation?
This is a fairly common technique. For example, this is from the TypeScript handbook: https://www.typescriptlang.org/docs/handbook/basic-types.html#never
> The never type is a subtype of, and assignable to, every type; however, no type is a subtype of, or assignable to, never (except never itself). Even any isn’t assignable to never.
Imagine the following scenario: function foo(callable(): int $computeSomething) { $magicNumber = $computeSomething(); } function bar(): noreturn { throw new Exception('bar'); } // Is completely type-safe as $magicNumber will never be assigned foo('bar'); // Without noreturn being a bottom type you'd have to do this foo(function(): int { bar(); }); We don't have callable types yet but it's common in other languages. The point is that, since noreturn will throw, terminate or never end, $magicNumber will never be assigned. This means effectively the return type of any function can be safely substituted with noreturn. The other benefit is that you can accurately typehint an overridden method. class Foo { function baz(): int { return 42; } } class Bar extends Foo { function baz(): noreturn { throw new Exception(); } } $bar = new Bar(); $bar->baz(); // IDE will know this always terminates qux(); // Dead code Not every language allows this but it does make sense semantically. It's not a deal breaker if we don't have it but given that the implementation is fairly simple I don't see why we wouldn't. Ilija

Marco Pivetta

5 years ago
Hey Aleksander, On Thu, Mar 11, 2021 at 8:25 AM Aleksander Machniak <alec@alec.pl> wrote:
> On 10.03.2021 20:28, Ben Ramsey wrote: > >> I don't like that type covariance would be allowed. Why such an > >> exception to the rules? > > > > It’s not an exception. Returns are covariant. Parameters are > > contravariant. Since `noreturn` is a subtype of all other types, it > > behaves as expected. > > I see it's a subtype, I don't get why. Wouldn't it be better to be a > separate type so return type covariance is not allowed (as it is with > void)? Was it a design decision or a side product of the implementation? >
`noreturn` is what's called the "bottom type", and it's a subtype of all types. It can sound counter-intuitive, but it is true that all methods in a subclass can be re-implemented with the bottom type as their return type (instead of their original one), and the system is still sound from a type perspective. Marco Pivetta http://twitter.com/Ocramius http://ocramius.github.com/

Sebastian Bergmann

5 years ago
Am 10.03.2021 um 19:06 schrieb Matthew Brown:
> Ondřej Mirtes and I present an RFC for the noreturn type: > https://wiki.php.net/rfc/noreturn_type
Thank you, Ondřej and Matt, for bringing this up. Makes sense to me, +1.

Dan Ackroyd

5 years ago
Hi Matt & Ondřej, One of the things that makes PHP different from other languages (and for better for a change) is that every function returns a value, even where there is no explicit return statement. This eliminates a large number of edge-cases in code like: function log_result(mixed $bar) {...} log_result($anyCallable()); is always valid in PHP, whereas in other languages similar code can either refuse to compile, or error out when run, or other things like 'undefined' variables. I.E. in other languages, there are three exit conditions: * no value returned * a value returned * function has no normal exit And so other languages need to indicate between 'void' and 'no return' But in PHP there are only two exit conditions*: * a value returned * function has no normal exit I (and others) brought this up during the void RFC: https://news-web.php.net/php.internals/88990 and said that null was the right choice over void, as it matches what the language actually does. That would have left void available to mean 'this function' does not exit normally. Unfortunately people in the community have started doing what I feared, and using void as 'no value is returned', which is not what the language actually _does_. I realise the above might be slightly discombobulating if, for example, some people had written large static code analyzers that had misinterpreted void like this. I think we should introduce null. But we shouldn't introduce 'noreturn' even if a large number have misunderstood what the behaviour of the language is. It might be appropriate for the other languages that are listed in the other language section, but it's not appropriate in PHP which is different to those languages. cheers Dan Ack * so the usage of null and void return types should be: function returns(): null { if (rand(0, 100) === 0) { throw new \Exception('Surprise!');} // intentionally no code } function never_returns(): void { if (rand(0, 100) === 0) { throw new \Exception('Surprise!');} while (1) {} } For both of them, there are exceptions to the declared return type, but otherwise 'returns' returns the value null, and 'never_returns' never returns a value.

Rowan Collins

5 years ago
Hi Dan, While I have some sympathy for your first point:
>I (and others) brought this up during the void RFC: >https://news-web.php.net/php.internals/88990 and said that null was >the right choice over void, as it matches what the language actually >does.
I disagree with your second, which doesn't follow at all:
>That would have left void available to mean 'this function' does not >exit normally.
Using "void" for this would be even more confusing than what we have now. If anything, "void" should have been reserved for an implementation that checked correct usage at the call site, as happens in other languages. Although, if someone can come up with an implementation of that, adding it with a suitable lead in time would still be possible. It's also something of a moot point, since even if we introduced a null return type (which would be a subtly different feature from void as currently implemented), we couldn't suddenly repurpose a keyword that's already used. So if you think "never returns" is something worth representing, it will need a new keyword, several options for which have been proposed. Regards,
-- Rowan Tommins [IMSoP]

Rowan Collins

5 years ago
On 11 March 2021 19:39:26 GMT, Dan Ackroyd <Danack@basereality.com> wrote:
>Unfortunately people in the community have started doing what I >feared, and using void as 'no value is returned', which is not what >the language actually _does_. > >I realise the above might be slightly discombobulating if, for >example, some people had written large static code analyzers that had >misinterpreted void like this.
I think it is you that is misinterpreting things. The "void" keyword explicitly signals the intent "this function does not return a value". People find that a useful thing to signal, even if the language still allows the function to be used in expression context. They also find it useful to be reminded "Hey, you know this function you're using as an expression? That makes no sense, because it doesn't return anything." You may not find that useful, but those that do are using "void" exactly as intended. Regards, Oh, and on this point:
-- Rowan Tommins [IMSoP]

Aaron Piotrowski

5 years ago
> On Mar 10, 2021, at 12:06 PM, Matthew Brown <matthewmatthew@gmail.com> wrote: > > Hey, > > Ondřej Mirtes and I present an RFC for the noreturn type: > https://wiki.php.net/rfc/noreturn_type > > The feature already exists in Hack (the primary inspiration) and is > currently supported by our static analysis tools inside docblocks, and we > feel there's a good argument for it to be supported by PHP itself. > > Thanks, > > Matt & Ondřej
Hi Matt & Ondřej, I wanted to give my +1 to this proposal. I was curious to see how fibers might interact with this declaration, since it is possible to create a fiber that can not return. So, I compiled your branch and gave it a try. ``` $fiber = new Fiber(function (): noreturn { while (true) { Fiber::suspend(\random_int(0, 100)); } }); $result = $fiber->start(); for ($i = 0; $result; ++$i) { echo $result, "\n"; $result = $fiber->resume(); } echo "Generated ", $i, " numbers before generating zero.\n"; ``` This short script works just as expected, cool! :-D Cheers, Aaron Piotrowski

Nikita Popov

5 years ago
On Wed, Mar 10, 2021 at 7:07 PM Matthew Brown <matthewmatthew@gmail.com> wrote:
> Hey, > > Ondřej Mirtes and I present an RFC for the noreturn type: > https://wiki.php.net/rfc/noreturn_type > > The feature already exists in Hack (the primary inspiration) and is > currently supported by our static analysis tools inside docblocks, and we > feel there's a good argument for it to be supported by PHP itself. > > Thanks, > > Matt & Ondřej
Thanks for the proposal! I think this is a nice addition. Regards, Nikita

Nikita Popov

5 years ago
On Wed, Mar 10, 2021 at 7:07 PM Matthew Brown <matthewmatthew@gmail.com> wrote:
> Hey, > > Ondřej Mirtes and I present an RFC for the noreturn type: > https://wiki.php.net/rfc/noreturn_type > > The feature already exists in Hack (the primary inspiration) and is > currently supported by our static analysis tools inside docblocks, and we > feel there's a good argument for it to be supported by PHP itself. > > Thanks, > > Matt & Ondřej >
Is it allowed to declare a noreturn function that returns by reference? function &foo(): noreturn {} Regards, Nikita

Marco Pivetta

5 years ago
Hey Nikita, On Fri, Mar 19, 2021, 14:35 Nikita Popov <nikita.ppv@gmail.com> wrote:
> > Is it allowed to declare a noreturn function that returns by reference? > > function &foo(): noreturn {} >
Given that `noreturn` means it should throw, loop forever or exit, how would a by-ref usage be applied/useful? Or is it a hint at a missing test?

Nikita Popov

5 years ago
On Fri, Mar 19, 2021 at 3:45 PM Marco Pivetta <ocramius@gmail.com> wrote:
> Hey Nikita, > > On Fri, Mar 19, 2021, 14:35 Nikita Popov <nikita.ppv@gmail.com> wrote: > >> >> Is it allowed to declare a noreturn function that returns by reference? >> >> function &foo(): noreturn {} >> > > Given that `noreturn` means it should throw, loop forever or exit, how > would a by-ref usage be applied/useful? > > Or is it a hint at a missing test? >
Mainly a hint for missing spec ;) Context is that we're considering to deprecate by-ref void return ( https://wiki.php.net/rfc/deprecations_php_8_1#return_by_reference_with_void_type), so it would make sense to me to prohibit this for noreturn from the start. However, I could also see an argument for why allowing it may be useful due to variance considerations. It would allow you to write something like this: <?php class A { public function &test(): int { ... } } class B extends A { public function &test(): noreturn { throw new Exception; } } While dropping the by-ref return on B::test() would be forbidden by variance (and I don't think we'd want to add more special rules here, like ignoring ref-return variance for noreturn functions). Regards, Nikita

Matthew Brown

5 years ago
On Fri, 19 Mar 2021 at 10:53, Nikita Popov <nikita.ppv@gmail.com> wrote:
> On Fri, Mar 19, 2021 at 3:45 PM Marco Pivetta <ocramius@gmail.com> wrote: > >> Hey Nikita, >> >> On Fri, Mar 19, 2021, 14:35 Nikita Popov <nikita.ppv@gmail.com> wrote: >> >>> >>> Is it allowed to declare a noreturn function that returns by reference? >>> >>> function &foo(): noreturn {} >>> >> >> Given that `noreturn` means it should throw, loop forever or exit, how >> would a by-ref usage be applied/useful? >> >> Or is it a hint at a missing test? >> > > Mainly a hint for missing spec ;) > > Context is that we're considering to deprecate by-ref void return ( > https://wiki.php.net/rfc/deprecations_php_8_1#return_by_reference_with_void_type), > so it would make sense to me to prohibit this for noreturn from the start. > > However, I could also see an argument for why allowing it may be useful > due to variance considerations. It would allow you to write something like > this: > > <?php > class A { > public function &test(): int { ... } > } > class B extends A { > public function &test(): noreturn { throw new Exception; } > } > > While dropping the by-ref return on B::test() would be forbidden by > variance (and I don't think we'd want to add more special rules here, like > ignoring ref-return variance for noreturn functions). > > Regards, > Nikita >
I think it should be allowed due to the variance considerations – I've updated the RFC to include your example.

Larry Garfield

5 years ago
On Wed, Mar 10, 2021, at 12:06 PM, Matthew Brown wrote:
> Hey, > > Ondřej Mirtes and I present an RFC for the noreturn type: > https://wiki.php.net/rfc/noreturn_type > > The feature already exists in Hack (the primary inspiration) and is > currently supported by our static analysis tools inside docblocks, and we > feel there's a good argument for it to be supported by PHP itself. > > Thanks, > > Matt & Ondřej
My main concern is around the covariance of inheritance. The example given: abstract class Person { abstract public function hasAgreedToTerms(): bool; } class Kid extends Person { public function hasAgreedToTerms(): noreturn { throw new \Exception('Kids cannot legally agree to terms'); } } While that may be technically correct from a type theory perspective (my type theory isn't strong enough to say either way), I don't feel like that obeys Liskov. If I have an array of Person objects, and I iterate them to check if they've all agreed to terms, I expect the return value to be a *usable* type in the Person interface or a subtype of it *that I can still use*. I cannot use Kid's return type, because it's by definition non-existent. That feels like a bad time bomb. Other than that concern, I'm fine with the spec. I would marginally prefer "never" over "noreturn", but not enough to vote against it just for that. --Larry Garfield

Matthew Brown

5 years ago
On Sat, 20 Mar 2021 at 11:35, Larry Garfield <larry@garfieldtech.com> wrote:
> My main concern is around the covariance of inheritance. The example > given: > > abstract class Person > { > abstract public function hasAgreedToTerms(): bool; > } > > class Kid extends Person > { > public function hasAgreedToTerms(): noreturn > { > throw new \Exception('Kids cannot legally agree to terms'); > } > } > > While that may be technically correct from a type theory perspective (my > type theory isn't strong enough to say either way), I don't feel like that > obeys Liskov.
It absolutely obeys Liskov, because noreturn is the subtype of all subtypes, aka the bottom type.
> If I have an array of Person objects, and I iterate them to check if > they've all agreed to terms, I expect the return value to be a *usable* > type in the Person interface or a subtype of it *that I can still use*. I > cannot use Kid::hasAgreedToTerms's return type, because it's by definition > non-existent.
Luckily your program will never have the chance to use its return type, because calling the method throws an exception.
> That feels like a bad time bomb. >
You might, in this scenario, add a `@throws` docblock and hope some sort of static analysis rule might catch the time bomb Another way that you can think of this is with throw expressions. The ternary in the function below is supposed to return `string`, or a subtype of `string` (the literal string "hello" is a subtype of `string`). The types are valid here if the type of `throw new Exception...` is treated as `noreturn`, and if `noreturn` is a subtype of `string`. ``` <?php function getString(): string { return rand(0, 1) ? "hello" : throw new \Exception('bad'); } ```
> Other than that concern, I'm fine with the spec. I would marginally > prefer "never" over "noreturn", but not enough to vote against it just for > that. >
There will be a separate vote for noreturn vs never!

Matthew Brown

5 years ago
If there are no more questions, we plan to open up voting for this on Tuesday March 30. There will be two votes — a 2/3 majority required for the feature, and a simple majority required for the name — “noreturn” vs “never”.

Ilija Tovilo

5 years ago
Hi Matthew
> Ondřej Mirtes and I present an RFC for the noreturn type: > https://wiki.php.net/rfc/noreturn_type > > The feature already exists in Hack (the primary inspiration) and is > currently supported by our static analysis tools inside docblocks, and we > feel there's a good argument for it to be supported by PHP itself.
Thanks for the RFC! I'm very much in support of it. Two small things: 1. Some magic methods like __toString currently require a specific return type (like string in that case). Since noreturn is a bottom type technically it should be possible to type hint those magic methods with noreturn. It's not a big issue if that's not possible, but it should be mentioned in the RFC. 2. noreturn is one of the few return types that would technically make sense for __construct (other than void). class Foo { public function __construct(): noreturn { throw new Exception(); } } new Foo(); bar(); // < Dead code Not sure this is worth supporting but I just wanted to mention it. Ilija

Matthew Brown

5 years ago
> On Mar 29, 2021, at 1:25 PM, Ilija Tovilo <tovilo.ilija@gmail.com> wrote: > > Hi Matthew > >> Ondřej Mirtes and I present an RFC for the noreturn type: >> https://wiki.php.net/rfc/noreturn_type >> >> The feature already exists in Hack (the primary inspiration) and is >> currently supported by our static analysis tools inside docblocks, and we >> feel there's a good argument for it to be supported by PHP itself. > > Thanks for the RFC! I'm very much in support of it. > > Two small things: > > 1. Some magic methods like __toString currently require a specific > return type (like string in that case). Since noreturn is a bottom > type technically it should be possible to type hint those magic > methods with noreturn. It's not a big issue if that's not possible, > but it should be mentioned in the RFC. > > 2. noreturn is one of the few return types that would technically make > sense for __construct (other than void). > > class Foo { > public function __construct(): noreturn { > throw new Exception(); > } > } > > new Foo(); > bar(); // < Dead code > > Not sure this is worth supporting but I just wanted to mention it. > > Ilija > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php >
Thanks, I’ll update the RFC to mention __toString, but I’ll steer clear of __construct

Andreas Hennings

5 years ago
Hello, I like the proposal. I also support the covariance. One question though. The RFC mentions possible future use of "nothing" as a bottom type for parameters in generics. This makes a lot of sense to me. Even without generics, it could be used for parameters in abstract methods. So why not already introduce "nothing" as the universal bottom type, and use it instead of "noreturn"? Can "noreturn" do anything that "nothing" can't? -- Andreas On Tue, 30 Mar 2021 at 07:18, Matthew Brown <matthewmatthew@gmail.com> wrote:

Ilija Tovilo

5 years ago
Hi Matthew
> I like the proposal. I also support the covariance. > > One question though. > The RFC mentions possible future use of "nothing" as a bottom type for > parameters in generics. This makes a lot of sense to me. Even without > generics, it could be used for parameters in abstract methods. > > So why not already introduce "nothing" as the universal bottom type, and > use it instead of "noreturn"? > Can "noreturn" do anything that "nothing" can't?
I'm also a little confused by this statement. The exact wording from the RFC is:
> Arguments for never: ... It's a full-fledged type, rather than a keyword used in a specific situation. A far-in-the-future generics proposal could use never as a placeholder inside contravariant generic types.
From what I understand, in Hack noreturn and never are both full-fledged types. Nothing is a bottom type while noreturn is not. Since in your proposal noreturn would also be a bottom type there's no reason why it couldn't be used in covariant or contravariant generic parameters. Please correct me if I'm missing something. Ilija

Matthew Brown

5 years ago
On Tue, 30 Mar 2021 at 13:51, Ilija Tovilo <tovilo.ilija@gmail.com> wrote:
> Hi Matthew > > > I like the proposal. I also support the covariance. > > > > One question though. > > The RFC mentions possible future use of "nothing" as a bottom type for > > parameters in generics. This makes a lot of sense to me. Even without > > generics, it could be used for parameters in abstract methods. > > > > So why not already introduce "nothing" as the universal bottom type, and > > use it instead of "noreturn"? > > Can "noreturn" do anything that "nothing" can't? > > I'm also a little confused by this statement. The exact wording from the > RFC is: > > > Arguments for never: ... It's a full-fledged type, rather than a keyword > used in a specific situation. A far-in-the-future generics proposal could > use never as a placeholder inside contravariant generic types. > > From what I understand, in Hack noreturn and never are both > full-fledged types. Nothing is a bottom type while noreturn is not. > Since in your proposal noreturn would also be a bottom type there's no > reason why it couldn't be used in covariant or contravariant generic > parameters. > > Please correct me if I'm missing something. > > Ilija > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php > >
In Hack it's a bit confusing. I think the Hack team ultimately decided that "nothing" was a better name for the bottom type than "noreturn", and confusingly introduced one while the other was still active. They have a long-term plan to deprecate "noreturn" in favour of "nothing" and stop supporting the former name, though it's unclear when that might happen.

Andreas Hennings

5 years ago
On Thu, 1 Apr 2021 at 15:05, Matthew Brown <matthewmatthew@gmail.com> wrote:
> > On Tue, 30 Mar 2021 at 13:51, Ilija Tovilo <tovilo.ilija@gmail.com> wrote: > > > Hi Matthew > > > > > I like the proposal. I also support the covariance. > > > > > > One question though. > > > The RFC mentions possible future use of "nothing" as a bottom type for > > > parameters in generics. This makes a lot of sense to me. Even without > > > generics, it could be used for parameters in abstract methods. > > > > > > So why not already introduce "nothing" as the universal bottom type, and > > > use it instead of "noreturn"? > > > Can "noreturn" do anything that "nothing" can't? > > > > I'm also a little confused by this statement. The exact wording from the > > RFC is: > > > > > Arguments for never: ... It's a full-fledged type, rather than a keyword > > used in a specific situation. A far-in-the-future generics proposal could > > use never as a placeholder inside contravariant generic types. > > > > From what I understand, in Hack noreturn and never are both > > full-fledged types. Nothing is a bottom type while noreturn is not. > > Since in your proposal noreturn would also be a bottom type there's no > > reason why it couldn't be used in covariant or contravariant generic > > parameters. > > > > Please correct me if I'm missing something. > > > > Ilija > > > > -- > > PHP Internals - PHP Runtime Development Mailing List > > To unsubscribe, visit: https://www.php.net/unsub.php > > > > > In Hack it's a bit confusing. I think the Hack team ultimately decided that > "nothing" was a better name for the bottom type than "noreturn", and > confusingly introduced one while the other was still active. > > They have a long-term plan to deprecate "noreturn" in favour of "nothing" > and stop supporting the former name, though it's unclear when that might > happen.
More reason for us to avoid this mistake, and introduce a name and concept that takes into account "bottom types", or not? We should decide now if we want to use the same keyword for everything, or if a bottom type should be distinct from a no-return behavior.