RFC: Not Null Assertion Operator

php.internals

Mihail Liahimov

1 year ago
Good afternoon. I would like to create an RFC on the implementation of the NOT null assertion operator. Do you think it makes sense to create it? I was able to implement the operator. I've already posted a draft in my github - https://github.com/rekmixa/php-src/tree/feature/not_null_assertion_operator An example of the implementation of this operator can be viewed in kotlin or in typescript. The point of it is that in places where we did not expect null, we should not make additional checks, but use this operator. It will also be convenient for highlighting in the IDE.

Ilija Tovilo

1 year ago
Hi Mihail Thanks for your proposal. On Wed, Feb 5, 2025 at 9:24 AM Mihail Liahimov <91liahim@gmail.com> wrote:
> > Good afternoon. I would like to create an RFC on the implementation of the NOT null assertion operator. Do you think it makes sense to create it? I was able to implement the operator. I've already posted a draft in my github - https://github.com/rekmixa/php-src/tree/feature/not_null_assertion_operator > An example of the implementation of this operator can be viewed in kotlin or in typescript. The point of it is that in places where we did not expect null, we should not make additional checks, but use this operator. It will also be convenient for highlighting in the IDE.
First off, it would be useful if you show some examples in your proposals. Especially for people who don't know Kotlin, it's not clear how such a feature would work. Looking at your patch, you're introducing the !-> operator, which presumably would error on (null)!->foo. A few thoughts: * This approach/patch seems unnecessarily limiting and complex. it would be easier to create a postfix operator ! that works on all expressions, and simply errors if null. This won't require much special handling in the engine. It would also allow you to do foo($bar!). TBH, this seems most useful for static analysis, but assert($bar) will do there too, so I'm not particularly convinced we need such a feature. * Especially in the case of property access on null, it would be worth considering whether we ever want to make this error by default, which seems like the general trajectory PHP has been taking. This is currently a warning (since PHP 8, and a notice since 5.0). If we rule that out, the feature might make more sense. Ilija

Mihail Liahimov

1 year ago
Thank you for your answer. Now I will give examples for better understanding. Simple examples from Typescript: let foo = ... foo!.bar() foo!.someProperty.baz() Examples of potentially using in PHP: Without this operator we writing this code: $foo = ... if ($foo === null) { throw new FooIsNullException(); } $foo->bar. With this operator: $foo!->bar $foo!->someProperty->method(); $foo!->someProperty->anotherProperty!->method(); I think the postfix operator would be illogical in PHP because my operator is similar to the existing nullsafe operator in syntax. And it would be strange if its syntax were different. Or we can implement both operator syntaxes: prefix for accessing properties, and postfix for use with variables, as in your example. Nullsafe: $foo?->bar; Not null assertion: $foo!->bar; If variable bar would be null - php will throw an exception. But now i dont know which exception it would be :) This operator will be useful in cases where a null value in a specific place will violate the domain logic. Usually we write either assertions or checks and throw our exceptions for this. But it seems to me that the not null assertion operator will help avoid writing unnecessary code. The problem, of course, will be catching errors. It is not clear how to catch errors by a specific value. I will think about it. ср, 5 февр. 2025 г. в 17:09, Ilija Tovilo <tovilo.ilija@gmail.com>:

Ilija Tovilo

1 year ago
Hi Mihail On Thu, Feb 6, 2025 at 1:51 PM Mihail Liahimov <91liahim@gmail.com> wrote:
> > Examples of potentially using in PHP: > Without this operator we writing this code: > > $foo!->bar > $foo!->someProperty->method(); > $foo!->someProperty->anotherProperty!->method(); > > I think the postfix operator would be illogical in PHP because my operator > is similar to the existing nullsafe operator in syntax. And it would be > strange if its syntax were different. > Or we can implement both operator syntaxes: prefix for accessing > properties, and postfix for use with variables, as in your example. > > Nullsafe: > $foo?->bar; > Not null assertion: > $foo!->bar;
With a postfix operator this would all work automatically, assuming that $foo!->bar can be parsed correctly as ($foo!)->bar. The, $foo! will check that $foo is not null, and if not, access the property bar on it.
> This operator will be useful in cases where a null value in a specific > place will violate the domain logic. Usually we write either assertions or > checks and throw our exceptions for this. But it seems to me that the not > null assertion operator will help avoid writing unnecessary code. The > problem, of course, will be catching errors. It is not clear how to catch > errors by a specific value. I will think about it.
I think, if such an operator were introduced, it should throw an Error rather than an Exception. Errors should generally not be caught, as they indicate logical errors in your program. There are two things to consider: * Is assert($foo !== null); $foo->bar; really much worse? I understand it requires two statements, so it cannot be used in all contexts. * Are we ever going to promote the (null)->prop warning to an Error? If so, is there still any appeal for this feature? E.g. it would automatically work on array access ($array!['foo']). Array access on null may be more controversial to promote to an Error. There are some other potential contexts, like foo($bar!), but you could argue this is already covered by parameter types. Ilija

Christoph Becker

1 year ago
On 06.02.2025 at 15:48, Ilija Tovilo wrote:
> * Is assert($foo !== null); $foo->bar; really much worse? I understand > it requires two statements, so it cannot be used in all contexts.
In my opinion, it is better, because you can completely disable the assertion checking in production.
> * Are we ever going to promote the (null)->prop warning to an Error? > If so, is there still any appeal for this feature?
I would rather avoid having ?->, !-> (or postfix !, which can easily be confused with prefix !), and regular ->. This is one to much. I'm fine with throwing on (null)->prop, but I'm also fine leaving this for static analysis. Christoph

Larry Garfield

1 year ago
On Thu, Feb 6, 2025, at 6:50 AM, Mihail Liahimov wrote:
> Thank you for your answer. Now I will give examples for better > understanding. > > Simple examples from Typescript: > > let foo = ... > foo!.bar() > foo!.someProperty.baz() > > Examples of potentially using in PHP: > Without this operator we writing this code: > > $foo = ... > > if ($foo === null) { > throw new FooIsNullException(); > } > > $foo->bar. > > With this operator: > > $foo!->bar > $foo!->someProperty->method(); > $foo!->someProperty->anotherProperty!->method(); > > I think the postfix operator would be illogical in PHP because my operator > is similar to the existing nullsafe operator in syntax. And it would be > strange if its syntax were different. > Or we can implement both operator syntaxes: prefix for accessing > properties, and postfix for use with variables, as in your example.
I am struggling to see the point of this in PHP. We don't have a compile-time check for that kind of null the way Kotlin or TypeScript do. At runtime, it would already throw a value I cannot control. With this... it would throw a value I cannot control. How is this a win? --Larry Garfield