Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:105113 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 50088 invoked from network); 5 Apr 2019 17:34:00 -0000 Received: from unknown (HELO out1-smtp.messagingengine.com) (66.111.4.25) by pb1.pair.com with SMTP; 5 Apr 2019 17:34:00 -0000 Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailout.nyi.internal (Postfix) with ESMTP id 6458C26AA7 for ; Fri, 5 Apr 2019 10:29:54 -0400 (EDT) Received: from imap26 ([10.202.2.76]) by compute7.internal (MEProxy); Fri, 05 Apr 2019 10:29:54 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=content-transfer-encoding:content-type :date:from:in-reply-to:message-id:mime-version:references :subject:to:x-me-proxy:x-me-proxy:x-me-sender:x-me-sender :x-sasl-enc; s=fm2; bh=DoTlPAGLG+TExvsDWep56X9EZayWT2ylyBRdUDMr/ Ak=; b=rAriJ7XBrlljnB9LZI28u5SjfHGRmyNu1ImrMV0e1+dEfDIuVDzkDPrNp P+BlLSyA0CSk+PHKWCsZLGPBCX6Lf7pMmNehqyewJWjJzLkb0XdOU2zTrc42afXB aqEIpHTzwHv5GvU0bfDqFx6gDSC1cQD0zyIFR8ZYHZRUqtyIHDE2KSHQAdJwpDPC ORYUzBCLttgAF/E7cQEWKt+Y240It+dFHYuA1w2yJOV+kDczZhmcAbmWih1MQQDn ZHOk+8ULYnXfzWTBP+zFPpE3MCdL/egs2Qsc1fNyCzwH3w8sVaIXRGtXCnw1wMlR 8dmY4VP6WPMKKl9UVbwjBHC1r8P5Q== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduuddrtdejgdejfeculddtuddrgedutddrtddtmd cutefuodetggdotefrodftvfcurfhrohhfihhlvgemucfhrghsthforghilhdpqfgfvfdp uffrtefokffrpgfnqfghnecuuegrihhlohhuthemuceftddtnecunecujfgurhepofgfgg fkjghffffhvffutgfgsehtqhertderreejnecuhfhrohhmpedfnfgrrhhrhicuifgrrhhf ihgvlhgufdcuoehlrghrrhihsehgrghrfhhivghlughtvggthhdrtghomheqnecuffhomh grihhnpehphhhprdhnvghtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehlrghrrhihsehg rghrfhhivghlughtvggthhdrtghomhenucevlhhushhtvghrufhiiigvpedt X-ME-Proxy: Received: by mailuser.nyi.internal (Postfix, from userid 501) id DA477B4349; Fri, 5 Apr 2019 10:29:53 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.1.6-329-gf4aae99-fmstable-20190329v1 Mime-Version: 1.0 X-Me-Personality: 10727885 Message-ID: <03b2e206-750f-4afb-806b-65ff77eb6893@www.fastmail.com> In-Reply-To: <76D63EA5-7F6D-43E6-ACC2-E55B5816BEF5@koalephant.com> References: <6d3be21f-d63a-3fc6-94ee-0bde8e313d66@xs4all.nl> <37bb451f-a1b2-4c69-91e2-f2ab6c4798e7@www.fastmail.com> <76D63EA5-7F6D-43E6-ACC2-E55B5816BEF5@koalephant.com> Date: Fri, 05 Apr 2019 10:29:53 -0400 To: internals@lists.php.net Content-Type: text/plain;charset=utf-8 Content-Transfer-Encoding: quoted-printable Subject: Re: [PHP-DEV] RFC Draft: Comprehensions From: larry@garfieldtech.com ("Larry Garfield") On Thu, Apr 4, 2019, at 10:46 PM, Stephen Reay wrote: > > Discussion: > >=20 > > For me, the inability to work with arrays is the big problem with th= e second approach. I very very often am type declaring my returns and p= arameters as `iterable`, which means I may have an array and not know it= . Using approach 2 means I suddenly really really need to care which kin= d of iterable it is, which defeats the purpose of `iterable`. Calling m= ethods on arrays, though, I'm pretty sure is out of scope. > >=20 > > Frankly were it not for that limitation I'd say I favor the chained = method style, as while it is more verbose it is also more self-documenti= ng. Given that limitation, I'm torn but would probably lean toward opti= on 1. And of course there's the "methods that apply to all traversable= objects" thing which is its own can of worms I know nothing about. > >=20 > > (If someone has a suggestion for how to resolve that disadvantage, I= 'd love to hear it.) > >=20 > > Those seem like the potential options. Any further thoughts? Or vo= lunteers? :-) > >=20 > > --Larry Garfield > >=20 > > --=20 > > PHP Internals - PHP Runtime Development Mailing List > > To unsubscribe, visit: http://www.php.net/unsub.php > >=20 >=20 > (Sorry, sent from wrong address, sending again!) >=20 > Hi Larry, >=20 > I=E2=80=99ve mostly ignored this thread until now - I find a lot of th= e=20 > =E2=80=9Cshorter syntax=E2=80=9D (i.e. the short closures RFC) to soun= d a lot like the=20 > arguments =E2=80=9CI don=E2=80=99t like semicolons/it has to be =E2=80= =98pretty'=E2=80=9D that happen=20 > in other language communities. In defense of terse syntax, it's not a question of "pretty". It's a que= stion of making it feasible to operate at a higher level of abstraction.= Really, generators didn't offer much of anything that couldn't be done= by defining and building an Iterator-implementing class. They're "just= " syntactic sugar. However, they allow the developer to conceptualize a= problem in a different way, and most of the machinery then falls away. = That means I can now think in terms of "call this function, then iterat= e the stream it gives me back" and within the function I can just have n= ormal logic with `yield` floating around as needed. Anything I do there= *could* be done with an Iterator class; I've done it some weird things = with Iterators before. But the ability to think in terms of an ad-hoc s= tream of values really changes the way you think about the problem, and = in a very good way. Similarly, short closures isn't about "let's make functions easier to wr= ite". That's a side effect. They should be thought of more as a way to= easily encapsulate "apply this expression to this set of values". So t= he advantage is not that $y=3D 5; array_map(fn($x) =3D> $x*$y, $arr); is less typing than array_map(function ($x) use ($y) { return $x * $y; }); It's that in the first option you don't think about it as a function, yo= u think about it as an expression applied over a set. That's a higher-o= rder mental operation, and once you start doing that you can conceptuali= ze the program in a different, more higher-order, less bug-prone way. Just like there's nothing you can do with foreach() that you can't also = do with for()... but foreach() lets you think in terms of "just do it to= everything" rather than think in terms of the machinery of iteration. I see comprehensions the same way. At one level they're "just" short sy= ntax for generators, but they're more about making it possible to reason= about your logic at a higher level, in a more declarative fashion. (There's probably a conference talk in there somewhere, from for to fore= ach to iterators to generators to comprehensions, each coming up one lev= el of abstraction.) > But the first example you give here, I can see the logical approach -=20= > as you say, it=E2=80=99s a currently-valid foreach statement, wrapped = in square=20 > brackets. Would it have to be a single line to parse, or could it be=20= > wrapped when the condition gets longer (yes I know it could just becom= e=20 > a regular generator then, I=E2=80=99m just wondering about what happen= s when=20 > someone adds a new line in there (in a language that historically=20 > doesn=E2=80=99t care about newlines) The RFC specifically says whitespace is irrelevant. If you want to brea= k a comprehension across multiple lines, you do you. But if it's gettin= g large enough that it's ugly to read that way it's a good sign you may = want to take a different approach. (A defined function with real foreac= h statements, multiple defined comprehensions that reference each other,= etc.) > I like the second concept a lot too, but how would this cope with for=20= > example: a userland class implements iterator but *also* defines a=20 > `filter(callback $fn): self` method for the exact same purposes were=20= > discussing. How is that handled? I have no idea at the moment. :-) That would be a possible BC issue. M= y first thought is that if an iterator defines filter(), map(), etc. its= elf then it's overriding the default behavior and can do what it wants, = but there's also possible function signature mismatches there. It may j= ust have to be a BC break in those cases. I am open to alternate sugges= tions. (That may push it to PHP 8, which would be unfortunate but if tha= t's the way it goes, that's the way it goes.) On Fri, Apr 5, 2019, at 3:41 AM, Micha=C5=82 Brzuchalski wrote: > Hi Larry, >=20 > pt., 5 kwi 2019 o 03:55 Larry Garfield napisa= =C5=82(a): >=20 > > > > Advantages: > > > > * Very compact. > > * Works for both arrays and traversables > > * Would play very nicely with the proposed spread operator for itera= bles ( > > https://wiki.php.net/rfc/spread_operator_for_array). > > >=20 > IMO not nicely cause spread operator in current proposal raises an err= or on > key preserved traversable[1]. > This means example like below would fail >=20 > $a =3D ['foo' =3D> true, ...[foreach($_GET as $key =3D> $value) yield = $key =3D> > $value]]; // error >=20 > [1] https://wiki.php.net/rfc/spread_operator_for_array#string_keys True; it's not a complete solution. Per the thread on spread string key= s may make a comeback. But I was thinking more of a case of: $arr =3D ...[foreach ($list as $k =3D> $v) yield $k =3D> $v]; For those cases where you really do want an array to operate on next, ra= ther than a generator. If you're in a situation where ... doesn't work,= iterator_to_array() still does; it's just more verbose. --Larry Garfield