Re: Nullsafe

From: Date: Wed, 04 Nov 2020 20:17:58 +0000
Subject: Re: Nullsafe
References: 1 2 3 4 5 6  Groups: php.internals 
Request: Send a blank email to internals+get-112184@lists.php.net to get a copy of this message
Hey, On Wed, Nov 4, 2020, 20:39 Eugene Sidelnyk <zsidelnik@gmail.com> wrote: > Yeah... Creating null was a huge mistake. > Now it is probably too late to fix that (maybe some new language can > introduce that). > > Y'all confusing Java's null (billion dollar mistake) with PHP's null. * In Java, null|object passes the object property and parameter type declaration, but crashes on . (-> operator in PHP). That means that the type system is fundamentally flawed. * In PHP, null|object does not pass the object property and parameter type declaration, and crashes on -> The PHP T|null type is almost equivalent to `data Maybe T = Just T | Nothing` from typed functional languages, and does not present the same "billion dollar mistake" flaws of Java. It is also an accurate and sufficient representation of "absence of value". That's why I linked the toString() vs (string) example in https://github.com/ShittySoft/symfony-live-berlin-2018-doctrine-tutorial/pull/3#issuecomment-460441229 Also, this was previously discussed in a similar way in https://externals.io/message/108369#108386 But what do you think about introducing special class NullObject? > You can really only apply the null object pattern (you can use the one from https://github.com/Ocramius/ProxyManager/blob/2.9.1/docs/null-object.md, which is relatively type-safe) when interactions with such an object leading to no effect are valid. In the example I wrote above: Let's assume following repository signature: ```php interface Accounts { /** @throws AccountNotFoundException */ public function get(AccountHolder $id): Account; } ``` In following usage: ```php $accounts->get($receiver) ->addFunds( $accounts->get($sender) ->detractFunds($amount) ); ``` Assuming -> were capable of operating with object|null (OP proposal), if (by accident) somebody decided to change this signature: ```diff interface Accounts { - /** @throws AccountNotFoundException */ - public function get(AccountHolder $id): Account; + public function get(AccountHolder $id): ?Account; } ``` In this scenario, what can happen is that money disappears, as I've written above: > In the above scenario, if the first $accounts->get() call > returns null for any reason, you may actually destroy money (funds detracted, but never added to another account). The same would happen if a NullObject were used: ```diff interface Accounts { - /** @throws AccountNotFoundException */ - public function get(AccountHolder $id): Account; + public function get(AccountHolder $id): NullObject<Account>|Account; } ``` Same scenario (slight variation): > In the above scenario, if the first $accounts->get() call > returns ` NullObject<Account> ` for any reason, you may actually destroy money (funds detracted, but never added to another account). I would say that embracing nullability **in a type-safe manner** (please use https://psalm.dev/ or https://phpstan.org/) leads to proper usage of null, where it correctly indicates cases where no value has been produced/found/calculated/etc. Null pointer exceptions are trivially avoided by using any of these relatively stable and well adopted static analysis tools, and we don't really need to fight windmills at all.

« previous php.internals (#112184) next »