Re: RFC Draft: Comprehensions

From: Date: Thu, 18 Apr 2019 17:00:53 +0000
Subject: Re: RFC Draft: Comprehensions
References: 1 2 3 4 5 6 7 8 9  Groups: php.internals 
Request: Send a blank email to internals+get-105319@lists.php.net to get a copy of this message
On Tue, Apr 9, 2019, at 3:31 AM, Stephen Reay wrote: > > > > On 5 Apr 2019, at 21:29, Larry Garfield <larry@garfieldtech.com> wrote: > > > > On Thu, Apr 4, 2019, at 10:46 PM, Stephen Reay wrote: > > > >>> Discussion: > >>> > >>> For me, the inability to work with arrays is the big problem with the second > >>> approach. I very very often am type declaring my returns and parameters 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 kind of iterable it is, which defeats > >>> the purpose of iterable. Calling methods on arrays, though, > >>> I'm pretty sure is out of scope. > >>> > >>> 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-documenting. Given that limitation, > >>> I'm torn but would probably lean toward option 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. > >>> > >>> (If someone has a suggestion for how to resolve that disadvantage, I'd love > >>> to hear it.) > >>> > >>> Those seem like the potential options. Any further thoughts? Or volunteers? :-) > >>> > >>> --Larry Garfield > >>> > >>> -- > >>> PHP Internals - PHP Runtime Development Mailing List > >>> To unsubscribe, visit: > >>> http://www.php.net/unsub.php > >>> > >> > >> (Sorry, sent from wrong address, sending again!) > >> > >> Hi Larry, > >> > >> I’ve mostly ignored this thread until now - I find a lot of the > >> “shorter syntax” (i.e. the short closures RFC) to sound a lot like the > >> arguments “I don’t like semicolons/it has to be ‘pretty'” that happen > >> in other language communities. > > > > In defense of terse syntax, it's not a question of "pretty". It's a > > question 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 iterate the stream it > > gives me back" and within the function I can just have normal 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 stream 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 > > write". 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 the advantage is not that > > > > $y= 5; > > array_map(fn($x) => $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, you think > > about it as an expression applied over a set. That's a higher-order mental operation, and once > > you start doing that you can conceptualize 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 > > syntax 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 foreach to > > iterators to generators to comprehensions, each coming up one level of abstraction.) > > > >> But the first example you give here, I can see the logical approach - > >> as you say, it’s a currently-valid foreach statement, wrapped in square > >> brackets. Would it have to be a single line to parse, or could it be > >> wrapped when the condition gets longer (yes I know it could just become > >> a regular generator then, I’m just wondering about what happens when > >> someone adds a new line in there (in a language that historically > >> doesn’t care about newlines) > > > > The RFC specifically says whitespace is irrelevant. If you want to break a comprehension > > across multiple lines, you do you. But if it's getting 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 foreach statements, multiple defined comprehensions that reference each other, etc.) > > > >> I like the second concept a lot too, but how would this cope with for > >> example: a userland class implements iterator but *also* defines a > >> filter(callback $fn): self method for the exact same > >> purposes were > >> discussing. How is that handled? > > > > I have no idea at the moment. :-) That would be a possible BC issue.. My first thought > > is that if an iterator defines filter(), map(), etc. itself then it's overriding the default > > behavior and can do what it wants, but there's also possible function signature mismatches > > there. It may just have to be a BC break in those cases. I am open to alternate suggestions. (That > > may push it to PHP 8, which would be unfortunate but if that's the way it goes, that's the > > way it goes.) > > > >> On Fri, Apr 5, 2019, at 3:41 AM, Michał Brzuchalski wrote: > >> Hi Larry, > >> > >> pt., 5 kwi 2019 o 03:55 Larry Garfield <larry@garfieldtech.com> napisał(a): > >> > >>> > >>> Advantages: > >>> > >>> * Very compact. > >>> * Works for both arrays and traversables > >>> * Would play very nicely with the proposed spread operator for iterables ( > >>> > >>> https://wiki.php.net/rfc/spread_operator_for_array). > >>> > >> > >> IMO not nicely cause spread operator in current proposal raises an error on > >> key preserved traversable[1]. > >> This means example like below would fail > >> > >> $a = ['foo' => true, ...[foreach($_GET as $key => $value) yield $key > >> => > >> $value]]; // error > >> > >> [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 keys may make a > > comeback. But I was thinking more of a case of: > > > > $arr = ...[foreach ($list as $k => $v) yield $k => $v]; > > > > For those cases where you really do want an array to operate on next, rather 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 > > > > -- > > PHP Internals - PHP Runtime Development Mailing List > > To unsubscribe, visit: http://www.php.net/unsub.php > > > > Hi Larry, > > Sorry I haven’t replied before now. > > I understand that there is an actual tangible benefit being pursued > here - but so many of the comments seem to be focussed around removing > every possible character due to some weird belief that less characters > is automatically “better”, and it always reminds of the “I don’t like > semicolons they're ugly” type comments that always come up in JS > communities. > > Best of luck! > > > Cheers > > Stephen Um. Isn't that what you just said above, in the email I replied to at length? Like, it's in the quoted text above... --Larry Garfield

« previous php.internals (#105319) next »