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.