Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:104709 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 31790 invoked from network); 14 Mar 2019 10:26:14 -0000 Received: from unknown (HELO mail-lj1-f196.google.com) (209.85.208.196) by pb1.pair.com with SMTP; 14 Mar 2019 10:26:14 -0000 Received: by mail-lj1-f196.google.com with SMTP id z20so3845627ljj.10 for ; Thu, 14 Mar 2019 00:16:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=rRC6EdZT+J0a+YGU387yARAVpqiWVkxIxuDbukt+YEc=; b=NADKFPruCqviXve9vkSc9cyiwvGBmZRQqDkf4l8CPf5G99sDu/mEc7VfOLe4mCGPOu fTdj9yj7UihkP9w+pIWeDLJkU5g+ILp7R033kilGsQT7LXjbyKYTzm1LyAdxdhoekUcl XimNM2GFC0VLYVTnNByH+40jPGa2lNnYFeORmBKZ0+ccvehrfwf4LLB0J3IFiwz2mI2M ll7ZvXAtOxpIMj7Xfm9zT4l0lR5Zf5yLVg6xHpDMfBkhZU3mwgY77xK40aETz6xVnW4N frqMo84Sca2AMbjSfwk/pi6aumX+oUcxsYjgF/gYlAhizoFQWDFFduFgL1KuW75/k28g EDSw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=rRC6EdZT+J0a+YGU387yARAVpqiWVkxIxuDbukt+YEc=; b=nZgQfCi4nQ2MVHS+blMnkUarqJZoMZ5Cs4vA/0AtupYlb1fwnOjvyhlM+s2kKsMCM/ 1WEjKX2ZkuvaB1bRz4gZeGB2+pZ4bxsibdYCnJzEGQWGzOOEuf4IXtAOEGwviDb11zdS rnG2VXeGcoHCg4CK7HQA6VndiG+cq8XQUlj67hUiEJLOVFnuyjKeEtChbmFClu8iElfa WsBySO4+ypGYrVgbIBx6eg3TUQohNpGGHDQCCGLkafAH4ZkVOfbCdBjCMcrDnkWR6gzN XMak3Iu378G+kUVN/rqWiDWTQTZkXdJQsrsk8tfqmr5CqRAYYIsVIdv6q0sDcBUuJ1wV 57rw== X-Gm-Message-State: APjAAAVV5TTFr3la9nqO/PIZciD6DeyXt0BC0kGgdNYN6fE5rWJj+jtn cYDV8YXYIOc9PIT18LWejK5s9X2IXHm6/tqNcCb/Tg== X-Google-Smtp-Source: APXvYqyFmDD4C2J2S7Jf+MXZ0kgpo5Hn5JqISfvKhLGCVDF/uaC+AeAr7XUPtwItV4C5fbLVsntfgkZkeOAuYA1Nb3k= X-Received: by 2002:a2e:9a58:: with SMTP id k24mr5104884ljj.136.1552547792983; Thu, 14 Mar 2019 00:16:32 -0700 (PDT) MIME-Version: 1.0 References: <6d3be21f-d63a-3fc6-94ee-0bde8e313d66@xs4all.nl> In-Reply-To: Date: Thu, 14 Mar 2019 08:16:20 +0100 Message-ID: To: Larry Garfield Cc: PHP Internals List Content-Type: multipart/alternative; boundary="000000000000b29a3e058408b34b" Subject: Re: [PHP-DEV] RFC Draft: Comprehensions From: michal.brzuchalski@gmail.com (=?UTF-8?Q?Micha=C5=82_Brzuchalski?=) --000000000000b29a3e058408b34b Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable czw., 14 mar 2019, 04:22 u=C5=BCytkownik Larry Garfield napisa=C5=82: > On Wed, Mar 13, 2019, at 6:30 PM, Rowan Collins wrote: > > On 13/03/2019 21:10, Dik Takken wrote: > > > So in practice, I expect that > > > using comprehensions as proposed in the new RFC will also require doi= ng > > > a lot of iterator_to_array(). A dual comprehension syntax could fix > that. > > > > > > At risk of complicating things further, might the solution to that be t= o > > have a shorter syntax for iterator_to_array in general? > > > > It's a shame array-casts are defined for arbitrary objects, else we > > could have (array)$iterator - and therefore (array)[foreach ($users as > > $user) yield $user->firstName] > > I am again going to reply to a bunch of people at once here... > > > If I can summarize the responses so far, they seem to fall into one of tw= o > categories: > > 1) Love the idea, but wouldn't short-closures be close enough? > > 2) Love the idea, but hate the particular syntax proposed. > > On the plus side, it seems almost everyone is on board in concept, so > yay. That of course just leaves the syntax bikeshedding, which is always > the fun part. > > As an aside, someone up-thread said that comprehensions were "an easier > way to write foreach loops", which is only true by accident. > Comprehensions are more formally a way of defining one set in relation to > another set. That is, they are a declarative relationship between one se= t > and another. While in PHP that ends up effectively being a short-hand fo= r > foreach loops, that's more an accidental implementation detail. The synt= ax > used by many other languages to achieve the same thing doesn't look at al= l > like loop syntax. > > To the question of having both a generator and array version, I would hav= e > to say no. As noted in the RFC, most cases where you'd want to use a > comprehension are not places where you'd be feeding the result into an > array function. On the off chance that you are converting the iterable > into an array is trivial enough that supporting, documenting, and learnin= g > two slightly different syntaxes seems a net negative. > > To Rowan's point, I would be fully in favor of an easier syntax > alternative to iterator_to_array(). I think that's rather similar > (although not identical) to the "run out an iterator" add-on mentioned in > the RFC. I would support that, but I think it's a bit orthogonal and > should not be a blocker for short-closures or for comprehensions. > > As for the specific syntax, I see a couple of options. > > 1) Assuming that short-lambdas get adopted and they can transparently > support generators, the following syntax becomes automatically possible: > > $gen =3D (fn() =3D> foreach($arr as $k =3D> $v) if ($k % 2) yield $v;)(); > > While that does work, there's an awful lot of symbol salad there: (fn() = =3D> > and ;)(); are both just gross and hard to type. I would consider that no= t > a full solution for comprehensions because of how clumsy it is. > Have you thought about adopting a keyword which fill look similar as short closures but by default yield instead of return. I'm thinking of something like that which looks close to short functions but shorter: $arr =3D [ 'apple' =3D> ['a' =3D> 1], 'orange' =3D> ['a' =3D> 2], ] $comprehension =3D from($arr as $k =3D> ['a' =3D> $a]) =3D> if ($k =3D=3D= =3D 'orange' || $a =3D=3D=3D 1) $a; $comprehension =3D from($arr as $k =3D> ['a' =3D> $a]) =3D> { if ($k =3D=3D=3D 'orange') yield $a; if ($a =3D=3D=3D 1) yield $a; }; The 'from' keyword indicates that it is going to yield from what put in the parenthesis. Probably it won't be ambiguous when nesting comprehension. The example includes also a list array destruct on purpose to show all what foreach can do. > 2) We could include an even-shorter-lambda syntax, potentially, or perhap= s > a short-lambda-based comprehension syntax. For example (and this may not > be parser friendly but it's just to demonstrate the idea): > > $gen =3D fn{ foreach($arr as $k =3D> $v) if ($k % 2) yield $v }; > > That would be a short-hand for a short-closure that has no parameters, an= d > we could detect the yield and self-execute. The language inside the > function body would still be a bit verbose, but it would technically be a= ny > legal single statement, which would offer some potentially interesting > (scary?) options. I would consider this an acceptable solution for > comprehensions-ish in PHP. > > 3) The specific syntax proposed in the RFC is Python-inspired and > PHP-ified, but there's no reason we need to stick to that. There are a > myriad of other syntaxes for comprehensions in other languages that we > could steal if they fit better, some of which wouldn't at all resemble > foreach loops and thus avoid the for/foreach confusion. > > Wikipedia of course has a large index of them we can mine: > > > https://en.wikipedia.org/wiki/Comparison_of_programming_languages_(list_c= omprehension) > > It appears that the most common syntax involves [] of some variety, which > pose parsing problems for PHP, but a few other options jump out at me as > possible syntaxes to pilfer: > > C# has this SQL-esque syntax (which may involve too many additional > language keywords): > > var ns =3D from x in Enumerable.Range(0,100) > where x*x > 3 > select x*2; > > Elixr, Erlang, and Haskell use the <- symbol, which... I don't think we > use anywhere else currently? In Elixir: > > for x <- 0..100, x * x > 3, do: x * 2 > > Java 8, Ruby, Rust, and Swift are very very similar, and use a fluent > syntax. The Rust example: > > (0..100).filter(|x| x * x > 3).map(|x| 2 * x).collect(); > > While that could not be taken as-is, of course, it does propose an > interesting alternative approach, if we limit comprehensions to Traversab= le > objects rather than any iterable (that is, exclude arrays): > > $t->filter(fn($v) =3D> expression)->filter(fn($k, $v) =3D> > expression)->map(fn($v) =3D> expression); > > Which would, in turn, each produce a generator that reduces the set or > finally yields. I am not sure I fully like this one, to be honest, as th= e > multiple inline short closures make it rather verbose and harder to follo= w > with the proposed short-closure syntax (and it would involve more functio= n > calls internally), but it's an option. (collect() in these languages see= ms > like it's the equivalent of iterator_to_array(); maybe that's another > alternative there as well?) > > Nemerle, which I've never heard of before, has this: > > $[x*2 | x in [0 .. 100], x*x > 3] > > Which, while $ is obviously already used, does suggest using one of the > other not-yet-used sigils that Nikita identified, which would let us > reorder the parameters to put the expression first if we wanted. For > example: > > ^[$x *2 | $k =3D> $v in $arr if $k %2] > > > In general, I see two alternatives: > > 1) Pass short closures and then include a special case of that special > case that effectively gives us comprehensions over foreach, if, and yield= , > but with fewer seemingly-stray characters. > > 2) Steal a completely different syntax from some other language that is > still terse but less confusing. The main alternatives to "square bracket= s > around a for loop" syntax seem to be: > > A) Chained filter() and map() methods > B) SQL-like keywords > C) Use <- somehow. > D) Use a different starting character before the [] so that the parser > knows some new funky order of stuff is coming. > > I am open to both options, of course contingent on someone willing and > able to code it. > > --Larry Garfield > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php Great work and I like the idea in general. BR, -- Micha=C5=82 Brzuchalski --000000000000b29a3e058408b34b--