[CONCEPT][DISCUSSION] Allow objects to declare emptiness and by extension truthiness

php.internals

Josh Bruce

6 years ago
Latest version as we zero in on what this is really about: https://bit.ly/php-0002 <https://bit.ly/php-0002> Other threads: 1. https://externals.io/message/110879 <https://externals.io/message/110879> 2. https://externals.io/message/110881 <https://externals.io/message/110881> Thanks for all the feedback so far! Definitely feels like progress. Cheers, Josh

Larry Garfield

6 years ago
On Sun, Jul 12, 2020, at 12:48 PM, Josh Bruce wrote:
> Latest version as we zero in on what this is really about: > https://bit.ly/php-0002 <https://bit.ly/php-0002> > > Other threads: > > 1. https://externals.io/message/110879 <https://externals.io/message/110879> > 2. https://externals.io/message/110881 <https://externals.io/message/110881> > > Thanks for all the feedback so far! Definitely feels like progress. > > Cheers, > Josh
Hi Josh. This is a big improvement, and I think focuses on the useful value-add a lot better. Basing it off of Countable rather than Stringable is, I think, a safer overall approach, especially as it then gets us toBool as effectively a side-effect. There's 2 additional improvements I'd suggest: 1) The 2 places that you have lists of "this thing produces true/false" could likely stand to be turned into tables to make it clearer, especially when demonstrating that isEmpty() and __toBool() are effectively opposites of each other so we get a 2-for-1 deal. 2) Include some less-random examples of real "empty" objects. Also, please be warned that the PHP wiki doesn't use Markdown. It uses some wonky proprietary ancient mess instead. Now that you have Wiki access you should probably start using the PHP Wiki instead of Github so that you don't have to convert a mess of nice formatting from Markdown to PHPWiki-down. I like this idea and wish I had the skillz to help implement it. :-) --Larry Garfield

Josh Bruce

6 years ago
>> Latest version as we zero in on what this is really about: >> https://bit.ly/php-0002 <https://bit.ly/php-0002> >> > 1) The 2 places that you have lists of "this thing produces true/false" could likely stand to be turned into tables to make it clearer, especially when demonstrating that isEmpty() and __toBool() are effectively opposites of each other so we get a 2-for-1 deal.
I appreciate this idea - done.
> > 2) Include some less-random examples of real "empty" objects. >
I’m having difficulty with this, to be honest. I think there are two reasons for this: 1. I avoid null to the point of going out of my way to make it not happen - including implementing “isEmpty” - simultaneously I’m having a hard time, which could mean it’s a solution looking for a problem (was thinking about a file cabinet with drawers that would accept folders). 2. I have a very specific use case where this would solve a problem for me. It mainly revolves around the ability in PHP to make an object in such a way that it “feels” like an array - and “feels” like a string - and can become an integer - but there’s no way to make the object feel like and be interacted with like a bool. I don’t want my use case to be the only reason a change like this is introduced to PHP - I want to make sure “it’s not just me” - you know?? Re the wiki: I can edit pages now, it doesn’t look like I can create them. There’s another thread I’ve been watching and I think I need more karma to make that a thing. I will continue working on this and if it generates enough pull then maybe I’ll be let in - I’ll also contribute where I can to start earning karma. Updated: https://bit.ly/php-0002 <https://bit.ly/php-0002> Cheers, Josh

Christoph Becker

6 years ago
On 13.07.2020 at 17:18, Josh Bruce wrote:
> Re the wiki: I can edit pages now, it doesn’t look like I can create them. There’s another thread I’ve been watching and I think I need more karma to make that a thing. I will continue working on this and if it generates enough pull then maybe I’ll be let in - I’ll also contribute where I can to start earning karma.
You have RFC karma now.
-- Christoph M. Becker

Josh Bruce

6 years ago
> On Jul 13, 2020, at 12:14 PM, Christoph M. Becker <cmbecker69@gmx.de> wrote: > > On 13.07.2020 at 17:18, Josh Bruce wrote: > >> Re the wiki: I can edit pages now, it doesn’t look like I can create them. There’s another thread I’ve been watching and I think I need more karma to make that a thing. I will continue working on this and if it generates enough pull then maybe I’ll be let in - I’ll also contribute where I can to start earning karma. > > You have RFC karma now.
Christoph: Wow, okay. Thank you! All: I’ve decided to go ahead and do one more round using GitHub (big changes - kind of a synthesis of directions so far based on feedback). Then I’ll spend time transferring it to a draft (or discussion??) and making sure I understand the process more than I do at present. Nikita: Re falsiness: Switching back to being more about truthiness and falsiness. Thanks for the feedback. Re nullsafe: I agree that nullsafe handles the issue of null being returned and it’s a welcomed workaround, but it doesn’t address the problem of null being returned instead of a false (empty) object of the desired type that can be acted upon - even if limited. Brings up the new question again: Under what circumstances would PHP return null without a developer explicitly asking it to (somewhere in the call chain) or without PHP error? Cheers, Josh

Josh Bruce

6 years ago
> On Jul 14, 2020, at 1:24 PM, Josh Bruce <josh@joshbruce.dev> wrote: > > >> On Jul 13, 2020, at 12:14 PM, Christoph M. Becker <cmbecker69@gmx.de> wrote: >> >> On 13.07.2020 at 17:18, Josh Bruce wrote: >> >>> Re the wiki: I can edit pages now, it doesn’t look like I can create them. There’s another thread I’ve been watching and I think I need more karma to make that a thing. I will continue working on this and if it generates enough pull then maybe I’ll be let in - I’ll also contribute where I can to start earning karma. >> >> You have RFC karma now. > > Christoph: Wow, okay. Thank you! > > All: I’ve decided to go ahead and do one more round using GitHub (big changes - kind of a synthesis of directions so far based on feedback). > > Then I’ll spend time transferring it to a draft (or discussion??) and making sure I understand the process more than I do at present. > > Nikita: > > Re falsiness: Switching back to being more about truthiness and falsiness. Thanks for the feedback. > > Re nullsafe: I agree that nullsafe handles the issue of null being returned and it’s a welcomed workaround, but it doesn’t address the problem of null being returned instead of a false (empty) object of the desired type that can be acted upon - even if limited. > > Brings up the new question again: Under what circumstances would PHP return null without a developer explicitly asking it to (somewhere in the call chain) or without PHP error? > > Cheers, > Josh >
ps. Link: https://bit.ly/php-0002 <https://bit.ly/php-0002> - sorry

Nikita Popov

6 years ago
On Sun, Jul 12, 2020 at 7:49 PM Josh Bruce <josh@joshbruce.dev> wrote:
> Latest version as we zero in on what this is really about: > https://bit.ly/php-0002 <https://bit.ly/php-0002> > > Other threads: > > 1. https://externals.io/message/110879 < > https://externals.io/message/110879> > 2. https://externals.io/message/110881 < > https://externals.io/message/110881> > > Thanks for all the feedback so far! Definitely feels like progress.
I have a really hard time understanding what is actually being proposed here. You mention the introduction of the Emptiable interface, but not how it influences empty() or (bool) casts. There's some examples in "Usage" that are possibly intended to illustrate this -- I suspect that a "return true" vs "return false" mixup has made them impossible to understand though. Some thoughts on the general domain: 1. I don't like the idea of decoupling empty() and (bool). empty($x) is currently the same as !$x (modulo notices), and changing that will make PHP's already messy implicit type conversion matrix even messier. 2. Coupling boolean casts to an "emptiness" concept seems somewhat dubious to me. That works for container structures, but what about something like new Bigint(0)? It would be quite odd to declare an integer "empty" to make it evaluate to false. 3. I'm generally not a fan of overloadable bool casts. We have exactly one object with an overloaded bool cast in PHP, and that's SimpleXMLElement. As far as I know, this has only caused issues. A big reason for that is that using "if ($foo->bar)" is a common idiom for checking "if ($foo->bar !== null)" -- one that works very reliably, with the exception of SimpleXMLElement. 4. I think if ($container->isEmpty()) is much clearer than if ($container) -- why would we want people to use the latter instead? Regards, Nikita

Josh Bruce

6 years ago
> > Latest version as we zero in on what this is really about: https://bit.ly/php-0002 <https://bit.ly/php-0002> <https://bit.ly/php-0002 <https://bit.ly/php-0002>> > > I have a really hard time understanding what is actually being proposed here. You mention the introduction of the Emptiable interface, but not how it influences empty() or (bool) casts. There's some examples in "Usage" that are possibly intended to illustrate this -- I suspect that a "return true" vs "return false" mixup has made them impossible to understand though. > > Some thoughts on the general domain: > > 1. I don't like the idea of decoupling empty() and (bool). empty($x) is currently the same as !$x (modulo notices), and changing that will make PHP's already messy implicit type conversion matrix even messier. >
Thanks for the feedback! Not all incorporated in the latest, due to timing: https://bit.ly/php-0002 Initially this started as a desire to be able to declare an object casting to bool (__toBool or something). After a couple rounds the relationship between empty() and bool surfaced. The question I’m volleying there is are they different concepts (a non-answer compared to a lie) and does it matter given the established norm. (Sounds like you’re in the established norm camp - I tend to lean that way as well.)
> 2. Coupling boolean casts to an "emptiness" concept seems somewhat dubious to me. That works for container structures, but what about something like new Bigint(0)? It would be quite odd to declare an integer "empty" to make it evaluate to false.
This seems counter to the first bullet point. They already are coupled. The result of empty() tends to be the opposite of casting bool - unless there’s an example I’m unaware of.
> > 3. I'm generally not a fan of overloadable bool casts. We have exactly one object with an overloaded bool cast in PHP, and that's SimpleXMLElement. As far as I know, this has only caused issues. A big reason for that is that using "if ($foo->bar)" is a common idiom for checking "if ($foo->bar !== null)" -- one that works very reliably, with the exception of SimpleXMLElement.
I wasn’t aware of this. Thank you! I will take a look and see what problems people are running into and how it’s implemented - at least from a developer perspective.
> 4. I think if ($container->isEmpty()) is much clearer than if ($container) -- why would we want people to use the latter instead?
Fair question. This made me raise the question in the draft and I’ll raise it here…under what circumstances would PHP return null from new. $instance = new MyClass(); If ($instance->isEmpty()) {} $inner = $instance->innerObject(); If ($innnerObject->isEmpty()) {} If I implement the innerObject() method to return null - and it does - then that call fails, because it’s null, which brings up your earlier point, I think. If ($innerObject) { // not null If ($innerObject->isEmpty()) { // two-step process with null-check } } // with the language feature If ($innerObject) { // I know it can give and receive messages, and is not empty } else { // I know it can give and receive messages, but is empty } I remember hearing what sounds like hyperbole but it said something like 40% of code written is guarding against null. I can totally see that being real so didn’t look much further into it. If we can guarantee that an object is that type of object - just happens to be empty, maybe we reduce or remove the need null-checks?? Cheers, Josh

Nikita Popov

6 years ago
On Mon, Jul 13, 2020 at 5:33 PM Josh Bruce <josh@joshbruce.dev> wrote:
> > >> Latest version as we zero in on what this is really about: >> https://bit.ly/php-0002 <https://bit.ly/php-0002> >> >> I have a really hard time understanding what is actually being proposed > here. You mention the introduction of the Emptiable interface, but not how > it influences empty() or (bool) casts. There's some examples in "Usage" > that are possibly intended to illustrate this -- I suspect that a "return > true" vs "return false" mixup has made them impossible to understand though. > > Some thoughts on the general domain: > > 1. I don't like the idea of decoupling empty() and (bool). empty($x) is > currently the same as !$x (modulo notices), and changing that will make > PHP's already messy implicit type conversion matrix even messier. > > > Thanks for the feedback! Not all incorporated in the latest, due to > timing: https://bit.ly/php-0002 > > Initially this started as a desire to be able to declare an object casting > to bool (__toBool or something). After a couple rounds the relationship > between empty() and bool surfaced. The question I’m volleying there is are > they different concepts (a non-answer compared to a lie) and does it matter > given the established norm. (Sounds like you’re in the established norm > camp - I tend to lean that way as well.) > > 2. Coupling boolean casts to an "emptiness" concept seems somewhat dubious > to me. That works for container structures, but what about something like > new Bigint(0)? It would be quite odd to declare an integer "empty" to make > it evaluate to false. > > > This seems counter to the first bullet point. They already are coupled. > The result of empty() tends to be the opposite of casting bool - unless > there’s an example I’m unaware of. >
Yes, they are coupled. The problem here is more that empty() is a misnomer, because it does not check emptiness, it checks falsyness. The big example is that empty("0") returns true, even though "0" is very clearly not an empty string.
> > 3. I'm generally not a fan of overloadable bool casts. We have exactly one > object with an overloaded bool cast in PHP, and that's SimpleXMLElement. As > far as I know, this has only caused issues. A big reason for that is that > using "if ($foo->bar)" is a common idiom for checking "if ($foo->bar !== > null)" -- one that works very reliably, with the exception of > SimpleXMLElement. > > > I wasn’t aware of this. Thank you! I will take a look and see what > problems people are running into and how it’s implemented - at least from a > developer perspective. > > 4. I think if ($container->isEmpty()) is much clearer than if ($container) > -- why would we want people to use the latter instead? > > > Fair question. This made me raise the question in the draft and I’ll raise > it here…under what circumstances would PHP return null from new. > > $instance = new MyClass(); > > If ($instance->isEmpty()) {} > > $inner = $instance->innerObject(); > > If ($innnerObject->isEmpty()) {} > > If I implement the innerObject() method to return null - and it does - > then that call fails, because it’s null, which brings up your earlier > point, I think. > > If ($innerObject) { > // not null > > If ($innerObject->isEmpty()) { > // two-step process with null-check > > } > } > > // with the language feature > If ($innerObject) { > // I know it can give and receive messages, and is not empty > > } else { > // I know it can give and receive messages, but is empty > > } >
The nullsafe operator proposal will allow you to write this as if ($innerObject?->isEmpty()) { } That is both concise, and very explicit. Just If ($innerObject) is not -- it could be intended as just a null check, or as a null or empty check, or only an empty check, under your proposal. Nikita