Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:92374 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 711 invoked from network); 17 Apr 2016 07:19:23 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 17 Apr 2016 07:19:23 -0000 Authentication-Results: pb1.pair.com smtp.mail=php@fleshgrinder.com; spf=permerror; sender-id=unknown Authentication-Results: pb1.pair.com header.from=php@fleshgrinder.com; sender-id=unknown Received-SPF: error (pb1.pair.com: domain fleshgrinder.com from 212.232.25.162 cause and error) X-PHP-List-Original-Sender: php@fleshgrinder.com X-Host-Fingerprint: 212.232.25.162 mx206.easyname.com Received: from [212.232.25.162] ([212.232.25.162:54716] helo=mx206.easyname.com) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id 53/27-32052-6F833175 for ; Sun, 17 Apr 2016 03:19:20 -0400 Received: from cable-81-173-133-226.netcologne.de ([81.173.133.226] helo=[192.168.178.20]) by mx.easyname.com with esmtpsa (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.84_2) (envelope-from ) id 1argzB-0002Vr-46; Sun, 17 Apr 2016 07:19:13 +0000 Reply-To: internals@lists.php.net References: <57103A46.6040803@garfieldtech.com> <5710BA79.5060108@lsces.co.uk> <57110DC5.8000007@garfieldtech.com> To: Larry Garfield , internals@lists.php.net Message-ID: <571338E6.50507@fleshgrinder.com> Date: Sun, 17 Apr 2016 09:19:02 +0200 User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Thunderbird/38.7.2 MIME-Version: 1.0 In-Reply-To: <57110DC5.8000007@garfieldtech.com> Content-Type: multipart/signed; micalg=pgp-sha256; protocol="application/pgp-signature"; boundary="EM4M1eFEIb3Mmt50xjEcsnw38budukR7q" X-ACL-Warn: X-DNSBL-BARRACUDACENTRAL Subject: Re: [PHP-DEV] [RFC] Nullable Return Type Declaration From: php@fleshgrinder.com (Fleshgrinder) --EM4M1eFEIb3Mmt50xjEcsnw38budukR7q Content-Type: multipart/mixed; boundary="CB3O2HbCVNmRJL9QXJuec0tE1PME28UhD" From: Fleshgrinder Reply-To: internals@lists.php.net To: Larry Garfield , internals@lists.php.net Message-ID: <571338E6.50507@fleshgrinder.com> Subject: Re: [PHP-DEV] [RFC] Nullable Return Type Declaration References: <57103A46.6040803@garfieldtech.com> <5710BA79.5060108@lsces.co.uk> <57110DC5.8000007@garfieldtech.com> In-Reply-To: <57110DC5.8000007@garfieldtech.com> --CB3O2HbCVNmRJL9QXJuec0tE1PME28UhD Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable On 4/15/2016 5:50 PM, Larry Garfield wrote: > That there are a few small cases where PHP's current design makes NULL = a > reasonable sentinel value (custom iterators, fread() as you mention, > etc.) does not mean that in most cases, returning ValueObject|Null is > rude and abusive to users of your API. Yes, end-of-file is not an > exceptional case so should not throw an exception. I completely agree > there. But "user not found" I'd argue is. (Or rather, if it's not an > exceptional case your data model is kinda broken to begin with, because= > why are you asking for a missing user?) Or you're better off having an= > "empty" value instead, such as an anonymous user object. That's still > type safe. >=20 I disagree here. Your user example with the anonymous user object works if I am asking for e.g. the creation of a session but it is a very different situation if I would be asking for a user profile. The fact that a user might have deleted her account is not an exceptional case, is is to be expected and should be handled accordingly. How is up to the caller. Otherwise any `array_key_exists($k, $a)` should result in an exception or some default value according to your logic here. I completely agree that `NULL` is not the best type and others languages have other means to solve the issue but absolutely every language has some way to indicate the absence of a meaningful value. PHP has `NULL` like many others and that is fine. The problem is not that we have `NULL` the problem is that it is just too often not checked if it can be `NULL`. Rust and many functional language solve this with an Option or Maybe that requires creation, allocation, and userland checks for every return and the compilers fail if you do not unpack it. Ceylon solves this with union types as we are discussing it right now, however, the difference to other languages is that the compiler will fail if you are not checking the return value and bugs are avoided in this way. This is something that we could adopt. http://ceylon-lang.org/documentation/faq/language-design/#optional_types The absence of something must be modellable. class ConstraintViolation { private ?Throwable $cause; private string $message; public function __construct( string $message, ?Throwable $cause =3D null ) { $this->message =3D $message; $this->cause =3D $cause; } public function getCause(): ?Throwable { return $this->cause; } public function hasCause(): bool { return isset($this->cause); } // ... } An example of a class I was just working on. How could, would, or should one model this without `NULL`? Throwing an exception? It is not exceptional for such an object and expected that there is no cause available. It is up to the caller how she wants to take care of this. /** @var ConstraintViolation $violation */ if ($violation->hasCause()) { // Handle cause ... } $cause =3D $violation->getCause(); if (isset($cause)) { // Handle cause ... } // Or maybe we just want it stringified? // Works nicely with `NULL`. :) echo $violation->getCause(); Throwing exceptions everywhere for non exceptional cases is a code smell too and I see that ever to often in current open source code. Especially throwing extremely low-level exception everywhere for real errors from which one should not recover (e.g. `InvalidArgumentException`) because they indicate developer mistakes and only add a lot of checks in production for no reason. That being said, the above could be rewritten t= o. class ConstraintViolation { public function getCause(): Throwable {} public function hasCause(): bool {} } This would mean that PHP emits an Error if someone calls `getCause` and there is no cause and there would be only one way to check: `hasCause`. This is a valid design decision since it minimizes the amount of possibilities to work with the class and avoids `NULL` altogether. However, the caller code did not really become less verbose; as was already illustrated in the above examples. Plus, the ability to directly use the `__toString`ability paired with `NULL` in a string is gone. Everything always has pros and cons and I do not think that there is one answer to all of these questions. Different languages handle this problem differently. PHP has `NULL` and we should keep it this way. To minimize bugs resulting from unchecked `NULL` usage a compiler feature could be implemented that warns a developer in such cases. We already have it for uncatched exceptions (although IDEs are currently not telling one about that; Eclipse does in Java though). --=20 Richard "Fleshgrinder" Fussenegger --CB3O2HbCVNmRJL9QXJuec0tE1PME28UhD-- --EM4M1eFEIb3Mmt50xjEcsnw38budukR7q Content-Type: application/pgp-signature; name="signature.asc" Content-Description: OpenPGP digital signature Content-Disposition: attachment; filename="signature.asc" -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAEBCAAGBQJXEzjtAAoJEOKkKcqFPVVrFtQP/3XcJfRPTSFHzIKvLkjkjo2R H2VEdjCczQPPPAl8QWJDgXTaIn18pxhWjzezHvmkmLn+yFTXqZTgq5lxnuXYje5Y QP6vl+irDwHzeKZKLKI6FwPc16JOwm/WUN1td8aXzOGG+fFieuFAx8fwR7wz8lRW a60UaBraTnwUU9E/8XXEyq/l7PGvWeUdr8ivIA0wJSpLNlOJpRm6BWU+H6E2b0qV cUbSGYM4zC8I516pP3KN/ojwFOTeN7RJJ0piDoArw5Sn+xGj2G8Nqa+DcCxJEyXK rvTlJVaeXzIdiTx5HcOYUdheC/eQTzISBHNFWZfhCwCLt7lHaMP+lTnbIDnSu5WK psvK6COQyrSN5F6WDGIP9yguaGZbZbNvMIIVICF5w+Tmz8Yu+XYE8pDS11wHnw7P WHvkAIIi8zutxZFMCvndnhk0JZV6yL7Cssb1U+Iee6WrxIhUuvDzKWwr49fgUIHA 00aEclxROWIOsZ3OUP+SVJFcf1twZ9uKPpu5lR7jhnsfZn/et09ZPqC6SpIZ55d6 /J1+b/DtypuD+auOo8vTA8K/r/BSMpYfh3LCRGnR/YkaXoH19GW2W3vYG4dF2viV jFW57XWJWge7nlr2VU5i2qIztEZHkEwbbRh4jkl/QajhV/YjhGbltdwVjCYKAgTS wPhKuWqjLyzOnCvUW6dd =eQ4h -----END PGP SIGNATURE----- --EM4M1eFEIb3Mmt50xjEcsnw38budukR7q--