Pavel,
On May 16, 2020, at 05:13, Pavel Patapau <[email protected]> wrote:
>
> Hello everyone,
>
> I want to propose new syntax addition - guard statement, that executes code
> only if expression equals false and must contain control-flow changing code,
> and written a respective RFC:
>
> https://wiki.php.net/rfc/guard_statement
> <https://wiki.php.net/rfc/unbundle_xmlprc>
>
> Implementation in progress.
>
> I started work before this proposal https://externals.io/message/110107 and
> respected some moments in the RFC.
>
>
> Thanks for consideration,
> Pavel
Regarding this part of the proposal:
> Body of statement must contain code that changes control flow: return, throw,
> goto. Also, in a loop context, you can use break or continue.
>
> If compiler doesn't find any of those statements, it will search selection
> type statements(if with else|try/catch/finally|switch) and ensures that every
> element of these statements contains return, throw, goto.
I feel that from an implementation standpoint, this could be fairly complex,
especially since code such as:
guard (COND) else exit;
guard (COND) else call_some_function_that_calls_exit();
ought to compile without warnings. (Exit was explicitly included in my original
proposal on the mailing list.) Some languages allow this by marking functions
with a noreturn attribute (C, Swift < 3). Swift >= 3 solves this problem by
having a "Never" return type, which is validated by Swift's type checker,
requiring all code paths to also call another function returning Never. (As an
implementation detail, Never is an enum with no cases.)
Otherwise, you would have to write
guard (COND) else {
exit;
return;
}
to satisfy the parser, which is silly.
I would suggest an alternative that is conceptually simpler and allows for this
use case.
We can observe that if we slightly loosen the restriction that the _compiler_
must be able to do a full call path analysis, a guard statement can also be
thought of as:
guard (COND) else {
STATEMENTS;
throw new \GuardFailureError;
}
That is, the else clause ends with a compiler-generated fatal error. This means
the compiler itself doesn't _have_ to do a full analysis of every call path in
the STATEMENTS to ensure proper exit; the runtime can trap as well.
This allows us to be a bit more flexible: if the compiler can prove one way or
the other, it can either fail compilation, or else omit generating the opcodes
for throwing the GuardFailureError. But code that the compiler _can't_ prove
(such as the previously mentioned code-that-calls-exit) should still be allowed.
If we later add language support for a noreturn attribute, or some other
mechanism to account for that, then we are in a position to allow for that
complexity in the parser and remove the runtime handling. It would obviously be
preferable if the compiler can catch errors in all cases, but when it can't
(and php's dynamicity makes this a hard problem), I think it's acceptable that
the runtime can serve as a fallback.
-John
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php