Comprehensions, Where Art Thou?

Tab Atkins Jr. jackalmage at
Mon Aug 11 12:30:00 PDT 2014

On Mon, Aug 11, 2014 at 11:13 AM, Brendan Eich <brendan at> wrote:
> Tab Atkins Jr. wrote:
>> No, that's standard.  It's not Pythonic to have comprehensions that
>> large, as it obscures rather than enlightens, particularly some of
>> those crazier nested ones that Dave is using.
> Dave was translating mostly-mechanically from prior source.

Yeah, but the result was code that violated common coding guidelines from
Python, and so wasn't very illuminating for the question of "what syntax
should we use for comprehensions?".

>> If your comprehension
>> doesn't fit in 80chars, you're probably doing something wrong, and
>> should break it down to a real for loop.
> See the original in Python from Peter Norvig, and an
> version based on my JS1.8 "port" of Peter's original:
> Did you find Peter's comprehensions overlong? I did not, but that's not to
> say anything about the original is "easy". It's a great read, especially
> the posted "literate code" form.

No, all of Peter's comprehensions are short and easy to comprehend.
 Comparing it with Dave's version, I think it's simply a matter of the JS
comprehensions requiring more syntax, and crossing the line from "easy to
read" to "hard to read".  Here's the one bit in particular that stands out:

unitlist = ([cross(rows, c) for c in cols] +
            [cross(r, cols) for r in rows] +
            [cross(rs, cs) for rs in ('ABC','DEF','GHI') for cs in

var unitlist
  = [for (c of cols)
       cross(rows, [c])]
    .concat([for (r of rows)
               cross([r], cols)])
    .concat([for (rs of ["ABC","DEF","GHI"])
               for (cs of ["123","456","789"])
                 cross(rs.split(""), cs.split(""))]);

Norvig's is simple and easy to read. Herman's is polluted with additional
method calls and more indentation.  If we remove the indentation...

var unitlist
  = [for (c of cols) cross(rows, [c])]
    .concat([for (r of rows) cross([r], cols)])
    .concat([for (rs of ["ABC","DEF","GHI"]) for (cs of
["123","456","789"]) cross(rs.split(""),

Now pretend that for-of works on strings... (maybe it already does, for all
I know, and Dave was just being paranoid)

var unitlist
  = [for (c of cols) cross(rows, c)]
    .concat([for (r of rows) cross(r, cols)])
    .concat([for (rs of ["ABC","DEF","GHI"]) for (cs of
["123","456","789"]) cross(rs,

Okay, it's still a little bit harder to read, due to the .concat() calls
and their attendant additional parens, and the parens around the for-of
bodies, but it's not *terribly* worse.  It's still bad enough that I don't
know if I'd write it.

(Man, now that I've looked at these for a bit, I really see the logic of
Python putting the value *before* the for.  It gives you an examplar value
of what the array will look like, right up front, before sliding in the
"and here's how you make the rest of them!" indicator.  It also means that
all three constructions have the cross() call, the important part, lined up
in front so you can see the parallel structure more easily.  This really
helps me comprehend the code, no pun intended.)

> Beyond the conciseness, comprehensions should afford engines the ability
> optimize and parallelize. One of the breakthroughs in removing
> comprehensions from ES6 was everyone wanting to generalize from 1 (Array)
> N>>1 (iterables, lazy and eager; ParallelArray; other array-likes).
> Rather than adding mappar or pmap, one can use receiver-dispatched methods
> polymorphically as in JS funky-OOP today, no need for new delimiters after
> [] and () around for/of/if comprehension syntax. We really are out of
> delimiters!

Oh, I agree with all this.  Python's out of delimiters, too, they just
happened to have had one more set available, so they could do dict/set
comprehensions.  They're stuck now as well. ^_^

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the es-discuss mailing list