Hacker News new | ask | show | jobs
by jibal 304 days ago
"the target"? The OP complaint is not that the statement exists, but that the output expression comes before the context that establishes its meaning. This is not just a problem for autocomplete, but people often report difficulties understanding complex comprehensions.

As for comprehensions themselves, ignoring that problem I find them a powerful and concise way to express a collection of computed values when that's possible. And I'm particularly fond of generator expressions (which you didn't mention) ... they often avoid unnecessary auxiliary memory, and cannot be replaced with an inline for loop--only with a generator function with a yield statement.

BTW, I don't understand your comment about types. What's the type of (x for x in foo()) ?

1 comments

That one is a generator[Any], and for others it could be set[Any], list[Any] or dict[Any]. You obviously don't get embedded type information, but you still do get the encapsulating type, which is better than an untyped for loop :)

I get that it's about how it's structured and ordered, but that is true for the "for..in" loops in every language as well: you first set the variable, and only then get the context — this just follows the same model as the for loops in the language, and it would be weird if it didn't.

"that is true for the "for..in" loops in every language as well"

No, not at all. The output expression is arbitrary ... it might be f(x, y, z) where all of those are set later. You're confusing the output expression with the loop variable, which is also stated in the comprehension and may or may not be the same as the output expression or part of it. "The same model as the for loops in the language", where the language includes Python, is the comprehension with the output expression moved from the beginning to the end. e.g., (bar(x) for x in foo()) is `for x in foo(): bar(x)`. More concretely: lst = [bar(x) for x in foo()] is functionally equivalent to lst = []; for x in foo(): lst.append(bar(x))

Again, "the output expression comes before the context that establishes its meaning." ... I thought that would be clear as day to anyone who is actually familiar with Python comprehensions.

P.S. I'm not going to respond to goalpost moving.

Note that I am not disputing the order is "inversed": all I am saying is that there are other common language features in most languages where things don't flow the same way, yet nobody finds it a huge problem.

It's like discussion of RPN or infix for calculations: both do the job, one is more rigorous and clear with no grouping/parentheses, yet we manage just fine with infix operators in our programming languages (or maybe not, perhaps all bugs are due to this? :)).

These are different points.

Just like you state a variable and some operations on it early in a comprehension, you do the same in a for loop: you don't know the type of it.

As you are typing the for loop in, your IDE does not know what is coming in as a context being iterated over to auto-complete, for instance (eg. imagine iterating over tuples with "for k, v in some_pairs:" — your editor does not even know if unpacking is possible).

Basically, what I am saying is that comprehensions are similarly "bad" as for loops, except they are more powerful and allow more expression types early.

C/C++ allow even crazier stuff in the "variable's" place in a for loop. Rust allows patterns, etc.

Typing is mostly a nice addendum I mentioned, that's not the core of my point.