array coalesce operator concept

php.internals

Mark Shust

9 years ago
Hello, I wanted to garnish feedback on a RFC proposal. This is just a concept at this point, and is inspired by the null coalesce operator. Code will error if a non-array value is passed through a looping feature. For example, this code: <?php $foo = "abc"; foreach ($foo as $bar) { echo $bar; } will result in the error: PHP Warning: Invalid argument supplied for foreach() in test.php on line 3 To prevent this, the logical solution is to wrap this in an is_array check: <?php $foo = "abc"; if (is_array($foo)) { foreach ($foo as $bar) { echo $bar; } } This code runs successfully and does not error out. For a syntactic sugar/improvement, this can be shorthand for executing the loop instead of wrapping the block within an is_array check: <?php $foo = "abc"; foreach (??$foo as $bar) { echo $bar; } Let me know your thoughts. Cheers, Mark

David Rodrigues

9 years ago
The idea is good, but I don't know if it is more clear than an 'if()' Em 11 de jul de 2017 12:15 PM, "Mark Shust" <mark@shust.com> escreveu:

Tony Marston

9 years ago
"David Rodrigues" wrote in message news:CAEsg9X2ECG62i7Z_Nu11kqr7yVBkmUcd3MxGt78ULAmpFx--_w@mail.gmail.com...
> >The idea is good, but I don't know if it is more clear than an 'if()'
I think that this proposal is totally ridiculous and should be shot down in flames. My reasoning is as follows: 1) There should be a rule that anything which can be achieved with 5 lines or less in userland code should be automatically excluded from becoming a change to the language. The cost of changing the language in order to get around the laziness of a small number of users versus the "benefit" of making the language more complicated for the rest of us, as well as adding to the maintenance burden is simply not worth it. 2) Proposals such as this violate the first rule of good programming which is to provide code which is readable and therefore understandable by others, and therefore maintainable. I don't know about you, but I find it much easier to read words than symbols. The idea that the code "if (is_array($foo))" is too verbose and should be replaced with a shorthand symbol is just too ridiculous for word. If any more of these shortcuts is implemented then I'm afraid that code will look too much like a bunch of hieroglyphics and become far less readable. Just my 2 cents worth.
-- Tony Marston

Walter Parker

9 years ago
On Thu, Jul 13, 2017 at 2:55 AM, Tony Marston <TonyMarston@hotmail.com> wrote:
> "David Rodrigues" wrote in message news:CAEsg9X2ECG62i7Z_Nu11kqr7 > yVBkmUcd3MxGt78ULAmpFx--_w@mail.gmail.com... > >> >> The idea is good, but I don't know if it is more clear than an 'if()' >> > > I think that this proposal is totally ridiculous and should be shot down > in flames. My reasoning is as follows: > > 1) There should be a rule that anything which can be achieved with 5 lines > or less in userland code should be automatically excluded from becoming a > change to the language. The cost of changing the language in order to get > around the laziness of a small number of users versus the "benefit" of > making the language more complicated for the rest of us, as well as adding > to the maintenance burden is simply not worth it. > > 2) Proposals such as this violate the first rule of good programming which > is to provide code which is readable and therefore understandable by > others, and therefore maintainable. I don't know about you, but I find it > much easier to read words than symbols. The idea that the code "if > (is_array($foo))" is too verbose and should be replaced with a shorthand > symbol is just too ridiculous for word. If any more of these shortcuts is > implemented then I'm afraid that code will look too much like a bunch of > hieroglyphics and become far less readable. > > Just my 2 cents worth. > > -- > Tony Marston > > > Em 11 de jul de 2017 12:15 PM, "Mark Shust" <mark@shust.com> escreveu: >> >> Hello, >>> >>> I wanted to garnish feedback on a RFC proposal. This is just a concept at >>> this point, and is inspired by the null coalesce operator. >>> >>> Code will error if a non-array value is passed through a looping feature. >>> For example, this code: >>> >>> <?php >>> >>> $foo = "abc"; >>> >>> foreach ($foo as $bar) { >>> >>> echo $bar; >>> >>> } >>> >>> >>> will result in the error: >>> >>> PHP Warning: Invalid argument supplied for foreach() in test.php on >>> line 3 >>> >>> >>> To prevent this, the logical solution is to wrap this in an is_array >>> check: >>> >>> <?php >>> >>> $foo = "abc"; >>> >>> if (is_array($foo)) { >>> >>> foreach ($foo as $bar) { >>> >>> echo $bar; >>> >>> } >>> >>> } >>> >>> >>> This code runs successfully and does not error out. For a syntactic >>> sugar/improvement, this can be shorthand for executing the loop instead >>> of >>> wrapping the block within an is_array check: >>> >>> >>> <?php >>> >>> $foo = "abc"; >>> >>> foreach (??$foo as $bar) { >>> >>> echo $bar; >>> >>> } >>> >>> >>> Let me know your thoughts. >>> >>> >>> Cheers, >>> Mark >>> >>> > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > >
The more I think about this, the more I think that the throwing a warning when the variable is not an array is the proper thing to do. The cost in missed mistakes is much larger than the tiny savings in code that some people would get. Walter
-- The greatest dangers to liberty lurk in insidious encroachment by men of zeal, well-meaning but without understanding. -- Justice Louis D. Brandeis

Ivan Enderlin @ Hoa

9 years ago
Hello :-), Thank you for the proposal. I have a question though: How is it different from: * `foreach ($foo ?: [] as $bar) { … }` if `$foo` does not exist, * `foreach ((array) $foo as $bar) { … }` if `$foo` is not an array. I understand your issue, but you can probably type your data with `iterable`, `Generator`, `array`, `Iterator`… Also, I am not sure that `??$x` really means `if (is_array($x)) { … }`. Regards. On 11.07.17 17:02, Mark Shust wrote:

Andreas Treichel

9 years ago
> PHP already exhibits the skipping behaviour (it only emits a warning > for the wrong type used in `foreach`, skips the loop, and then > continues with remaining code).
Yes, a warning is not an error. If someone dont care about warnings from error prone code, set the error_reporting accordingly to hide the messages. With the following code you do not even get a warning about a undefined variable. foreach($foobar ?? [] as $value) { var_dump($value); }

Rowan Collins

9 years ago
On 11 July 2017 16:02:18 BST, Mark Shust <mark@shust.com> wrote:
>For a syntactic >sugar/improvement, this can be shorthand for executing the loop instead >of >wrapping the block within an is_array check: > > ><?php > >$foo = "abc"; > >foreach (??$foo as $bar) { > > echo $bar; > >}
Hi! I think there's definitely the start of a good idea here, but the syntax you suggest doesn't read quite right. As has been pointed out, this differs from existing features in two ways: - the special handling is for any non-iterable value, not just null or empty/falsey values, for which you could use $foo??[] and $foo?:[] respectively - the handling is to skip the loop, not loop once assigning $bar to the scalar value, as would happen with (array)$foo The challenge, then, is to come up with some syntax that somehow suggests these rules. The "??" is too much like the null coalesce, which would be misleading. The only idea that immediately comes to mind is a keyword: foreach ifarray ($foo as $bar) { I can't say I'm that keen on that syntax, but maybe it will inspire someone else. Regards,
-- Rowan Collins [IMSoP]

Mark Shust

9 years ago
Thanks for the great feedback. Based on the last mindset on keyword syntax, this comes to mind, intended to be used similarly to the 'use' keyword when used within the context of a closure: foreach ($foo as $bar) if (is_array) { ... } I don't think this is a vast improvement over wrapping this within an is_array check, however it does avoid the additional nest/wrapping. I was hoping for something that reads a bit more concisely or with a bit more syntactical sugar than the above. I think this does read nicely though. Cheers, Mark On Tue, Jul 11, 2017 at 1:50 PM Rowan Collins <rowan.collins@gmail.com> wrote:

Aidan Woods

9 years ago
If you were willing to accept ``` foreach ($foo as $bar) if (is_array) { ... } ``` as a solution, then you might as well use ``` if (is_array($foo)) foreach ($foo as $bar) { ... } ``` I wonder if this could be better achieved by expanding what the error suppression operator `@` can do? This entire behaviour seems more like an error suppression action on `foreach` to me, otherwise should we consider coalescing operators for other types/creating a more generic one? Going back to the error suppression operator: e.g. perhaps ``` foreach ($foo @as $bar) { ... } ``` could prevent skip past execution of the entire foreach block if there is an error using $foo as an array. So might make most sense to place the `@` on `as`, IMO, but I guess arguments could be made to place it like `@foreach ($foo as $bar)` or `foreach @($foo as $bar)`. Regards, Aidan On 11 July 2017 at 20:06, Mark Shust <mark@shust.com> wrote:

Mark Shust

9 years ago
Aidan, Fantastic suggestion (@as) -- that is really the succinctness I was initially looking for, and I think the intention makes a lot of sense. My only concern/issue would be to make sure that isn't considered a 'suppressor' -- but it's actual intent is to skip the execution of the foreach to prevent the error/loop from occurring (rather than just suppressing an error). Cheers, Mark On Tue, Jul 11, 2017 at 4:05 PM Aidan Woods <aidantwoods@gmail.com> wrote:

Aidan Woods

9 years ago
In theory you'd only *need* it be considered a suppressor? PHP already exhibits the skipping behaviour (it only emits a warning for the wrong type used in `foreach`, skips the loop, and then continues with remaining code). No harm in/there is probably value in, making that skipping intent explicit in a RFC though, but in terms of a patch, the warning would only need be suppressed as far as I can tell? Another thing I meant to mention -- this should not only be useful for arrays, but for any `Traversable` too (i.e. it should suppress errors generated in using a type not compatible with being iterated over in a `foreach` loop, and not just if the type is not array). Kind regards, Aidan On 12 July 2017 at 02:50, Mark Shust <mark@shust.com> wrote:

Mark Shust

9 years ago
Hi Aidan, I think you are correct on all points. The initial emit is just a warning, so I think a suppressor will work just fine, since it does just pass over the foreach if a traversable isn't passed in. I could see this being helpful as it makes wrapping an if block around a foreach not needed anymore (and in turn indenting the foreach another level), replacing it with just a single character. I also think for those that use linting tools and flag error suppressions, that an @as definition could be easily ignored from such a linter. I develop with warnings on, and see error suppressions as a sort of code smell, however I think the @as definition could be really useful. Cheers, Mark On Wed, Jul 12, 2017 at 4:22 AM Aidan Woods <aidantwoods@gmail.com> wrote:

Stas Malyshev

9 years ago
Hi!
> Code will error if a non-array value is passed through a looping feature. > For example, this code: > > <?php > > $foo = "abc"; > > foreach ($foo as $bar) {
Looks like $foo??[] would work here. If $foo is something like false or null, that is. If it's not, this is probably a serious bug (why would you iterate on something that is a number or a non-iterable object) and should be either fixed or resolved explicitly, not hidden.
-- Stas Malyshev smalyshev@gmail.com

Mark Shust

9 years ago
Stas, Wow, for some reason it didn't occur to me to try that. Confirming the following works: foreach ($foo ?? [] as $bar) { echo $bar; } I think the biggest need for this is if the value is null. Guess it's case-closed :) Might be a good idea to add this to the docs, pretty neat. Mark On Wed, Jul 12, 2017 at 2:00 PM Stanislav Malyshev <smalyshev@gmail.com> wrote: