Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:104701 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 99666 invoked from network); 14 Mar 2019 00:20:08 -0000 Received: from unknown (HELO lb3-smtp-cloud8.xs4all.net) (194.109.24.29) by pb1.pair.com with SMTP; 14 Mar 2019 00:20:08 -0000 Received: from [IPv6:2001:983:6fc5:1:3d21:b3f3:3023:64fe] ([IPv6:2001:983:6fc5:1:3d21:b3f3:3023:64fe]) by smtp-cloud8.xs4all.net with ESMTPA id 4B8kho9ZR4HFn4B8mhRQwM; Wed, 13 Mar 2019 22:10:21 +0100 To: internals@lists.php.net References: Message-ID: <6d3be21f-d63a-3fc6-94ee-0bde8e313d66@xs4all.nl> Date: Wed, 13 Mar 2019 22:10:18 +0100 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.5.1 MIME-Version: 1.0 In-Reply-To: Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit X-CMAE-Envelope: MS4wfL6E26tvlDmHlYt3+Om01EgWeDzl5S75dgnfrT/wwljIumem/+pKZBczy8XAlXYthEbKCwLkZvsxLKWXFsPsIBIKppyEzkUUs7iyd9aAU+p30GGfBD1L UFDQmH3Zhin6miVOkAR0GIbceABjWWx/cOrEYSvRV65M9pELQUk/Bq9yGZZzmxeaDmxwSLNrRvOQ4Bs2KXYwW971SUYfpJlw4naQEJZVv299F8gsemTBNFw+ WqgqhtRt1larntB2e72zMK5BjnvevPtdv2nuM/4xoX0= Subject: Re: [PHP-DEV] RFC Draft: Comprehensions From: d.takken@xs4all.nl (Dik Takken) On 11-03-19 05:29, Larry Garfield wrote: > Sara and I tried putting the expression first, as in Python, but that made the lexer very unhappy There is another possible reason to put the expression last: It preserves the ordering of the intended foreach loop. What I mean to say is this: One can change a loop into a comprehension by simply removing the newlines, braces, etc. Other than that, the various elements stay in the same place. For me, this makes it easier to 'see' the intended loop in the comprehension. I have always found the Python syntax to be confusing in this regard. On 11-03-19 13:16, Nikita Popov wrote: > I've brought up a similar proposal a few years ago, probably around the > time generators were first introduced: https://externals.io/message/61021 May I please point at one particularly nice detail in Nikita's proposal: A dual syntax for both array comprehensions and generator expressions: $arr = [foreach ($users as $user) yield $user->firstName] $gen = (foreach ($users as $user) yield $user->firstName) I would love to see a dual syntax included in the current proposal as well. I think it makes sense considering the fact that many functions in PHP only accept arrays, not generators. So in practice, I expect that using comprehensions as proposed in the new RFC will also require doing a lot of iterator_to_array(). A dual comprehension syntax could fix that. One little remark about the array comprehension syntax: Using a keyword other than "yield" would make the difference between the two more obvious. Perhaps the array comprehension could use "return": $arr = [foreach ($users as $user) return $user->firstName] $gen = (foreach ($users as $user) yield $user->firstName) > I think my main point of feedback would be to stick closer to existing PHP > syntax, even if it costs us some brevity. I would prefer > > $gen = [foreach ($list as $x) if ($x % 2) yield $x * 2]; > > over > > $gen = [for $list as $x if $x % 2 yield $x * 2]; > > The latter is nice in languages that generally use "for" for this purpose > and generally allow omitting parentheses, but I don't think it's good to > introduce this kind of syntax inconsistency in one place. Keeping the parenthesis would seem to be more consistent indeed. Omitting the curly brackets of a "foreach" loop is valid syntax in current PHP while omitting the parenthesis from the "foreach" and "if" is not. However, the RFC also points out that the syntax should be limited compared to a "foreach" loop, which makes sense. This makes me want to favor the syntax as proposed, without the parenthesis. The "full syntax" with parenthesis kind of suggests that comprehension syntax is no different than a regular foreach loop, supporting the existing if / else syntax, etc, but on a single line. That level of similarity might be confusing. For example, if I can write: if ($x % 2) yield $x * 2; and if ($x % 2) yield $x * 2; else yield $x; then why is it that I can write: [foreach ($list as $x) if ($x % 2) yield $x * 2] but not: [foreach ($list as $x) if ($x % 2) yield $x * 2; else yield $x] Bottom line: If comprehensions aim to provide an alternative syntax to foreach loops, with different rules, why try to make them look exactly like foreach loops? That could be confusing. Also note that Python list comprehensions basically show the same "inconsistency" as the proposed PHP comprehensions: In PHP, parenthesis are required after "foreach" or "if". The RFC proposes to omit them in comprehensions. In Python, colons are required after "for" and "if". Python comprehensions omit these. Not that "Python has it too" is a valid argument for anything at all though... I do agree that using "foreach" in stead of "for" may be a better choice. The proposed comprehensions are compressed foreach loops. In my mind, I want to think "foreach" when I see a comprehension, not "for". On 12-03-19 09:54, Kalle Sommer Nielsen wrote: > One more thing that kinda "annoys" me / what I base my above statement > on is; when reading some of the example is that the code examples > given, as in the code inside a Comprehension does not look very > PHP-ish besides the $-sigil and I do not like the idea of having "two" > syntaxes for PHP where one is only available in a very narrow-, > specific context and I feel it would be prone to potential errors. I fully understand this feeling. It's new to PHP and looks quite weird at first. Many of us know comprehensions from the Python world. Maybe the association with Python is so strong that the very concept of comprehensions feels Pythonic and not something that fits into PHP. I was skeptical about comprehensions myself when I started coding in Python. However, after getting used to them, I must admit that I find comprehensions easier to read than traditional loops. When they are short, that is. :) Looking at a comprehension, I can still 'see' the intended loop. Only quicker, because there is less code to scan. I would really like to encourage trying to step over that initial gosh-that's-weird feeling and consider what it could offer for PHP. On 12-03-19 16:42, Levi Morrison wrote: > Look at this example from the RFC: > > $result = (function() use ($table) { > foreach ($table as $num => $row) { > if ($num % 2 == 0) { > foreach ($row as $col => $val) { > if ($col >= 3) { > yield $num => $val; > } > } > } > } > })(); > > We could use this syntax today: > > $result = (function () { > foreach ($table as $num => $row) > if ($num % 2 == 0) > foreach ($row as $col => $val) > if ($col >= 3) > yield $num => $val; > })(); > > Compare that to this code using comprehensions, using the same whitespace style: > > $result = (for $table as $num => $row > if $num %2 ==0 > for $row as $col => $value > if $col >= 3 > yield $num => $val > ); > > In my opinion there are no meaningful differences here, and nothing > prevents you from using the all-in-one-line style if you care to. For bigger loop constructs, the advantage of comprehensions is indeed less obvious. In Python code, I find myself using comprehensions to replace mostly simple loops. That is where they really shine I think. Omitting curly brackets and using the all-in-one-line style is indeed possible, which closes the gap with closures even further. However, in practice the brackets are typically enforced by code style checkers, for good reason. In comprehensions, they can be safely omitted. > Oof, that sucks and I didn't even have to bind any variables. But if > we had shorter closures (this is JavaScript style) then it's fine > again: > > $result = array_map(($num) => intval($num, 16), $hex_numbers); > > My point is, closures are the major culprit. We really need shorter closures. That is one great example of how short closures might do the job. However, this assumes that what you need as output is an array. As proposed in the RFC, comprehensions would be generators. In the case where the above example would need to create a generator in stead of an array, a comprehension would be preferable over a closure. I think both short closures and comprehensions have great potential, I don't think we should pick one or the other. On 13-03-19 21:42, Stanislav Malyshev wrote: > Also agree about parentheses - reading a complex expression without > separators would be annoying. I know python loves to do this but even in > an IDE with highlighter it's not always easy to quickly figure out which > part belongs where. Delimiting it would make it easier IMHO, and also > allows again to carry over the intuition of how foreach() and if() work > from already known constructs. Only, the intuition of how "foreach" and "if" works does not fully apply due to the limited syntax of comprehensions. For example, you can't pair the "if" with an "else" in the current proposal. Maybe that could be supported as well, but that is not my point. If comprehensions start looking like familiar foreach loops but do not work the same way, would that not be confusing? Kind regards, Dik Takken