On Sat, 3 Apr 2021 at 12:30, Benjamin Eberlei <kont...@beberlei.de> wrote:
> > But adding a new keyword "noreturn" would not be necessary, it could just > be an Attribute as i said in my first e-mail explaining my no-vote: > > #[NoReturn] // sets a function flag modifying the void behavior > public function foo(): nothing { > return; // throws if it reaches this point > } > > This would be closer to what Psalm and PHP-Stan use at the moment if we > replace nothing with void. > > The problem is that "void" is already not perfect, since the callside > doesn't care about "return null" with no return type vs "return" + void > return type. > > If we had "nothing" and "null" instead of "void", and we'd say like PHP > works, "return;" actually means "return null;", then: > > function foo(): nothing { > return; // Error: cannot return null from a function that returns > nothing. > } > function bar(): null { > return; > // or return null; > } > > This would more consistently tie into union types where |null is allowed, > however on its own it is not: "foo() : null => error". > > As Levi said, this noreturn/never just perpetuates/amplifies the existing > void mistake and feels off, given that other recent changes to PHP have > been more bold, towards removing inconsistencies. > > Clearly comparisons of "noreturn"/"never" to "void" are a bit of a minefield, because a number of contributors feel that void was a mistake, that its implementation doesn't feel PHP-like. While I disagree that our proposal is intrinsically connected with the void one – noreturn/never could work equally well with a "null" return — our proposal does perpetuate one idea behind "void": that PHP can benefit from types found in other languages and type systems, and especially types found in Hack. It seems like some of the debate is over whether "noreturn"/"never" is a behaviour or a type. If it were purely a behaviour, with no meaning as a type, an Attribute would be a much more appropriate location. It's not just a behaviour, though — it is a type that follows variance rules, and it's a type that PHP can check. If "void" returns are too much of a distraction, think instead of "object" return type declarations: When executing the function function returnsObject($o) : object { if (rand(0, 1)) { return $o; } } Here PHP's engine checks two separate behaviours 1. when the function explicitly returns, does it return an object? 2. does the function ever finish without returning or throwing or exiting? Only the first actually involves a strict type check. The second is a generic behaviour check, triggered by the existence of a return type. This is essentially the same check that we want to trigger with "noreturn"/"never". In fact, as someone recently pointed out, running the following code *today* produces similar errors to the ones we propose: function php7Redirect() : noreturn { if (rand(0, 1)) { return "bad"; // Fatal error: Uncaught TypeError } header("Location: https://php.net"); exit; // OK } Our RFC makes this code explicitly legal, and adds covariance. Indeed our implementation is small because it correctly treats "noreturn"/"never" as a type, allowing us to use the existing return type handling.