Re: RFC Draft: Comprehensions
| From: | Larry Garfield | 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