foo = [transform(bar) for bar in baz.list() if condition(bar)] ?
Seems very readable and expressive. Or are you complaining about how they execute?Also \ used judiciously with proper indentation can break statements over multiple lines without too much pain.
foo = baz.list().filter{ bar => condition(bar) }.map(transform(_)).toList
If it's your first time looking at Scala, you'd probably be like, "What the fuck is that shit?" but as you learn the language, these types of patterns become common and make a lot of sense.I mean it's not like weird rules in natural language. At least the grammars for computer languages are strict, with very few edge cases (compared to human/spoken language).
foo = baz.list().filter(condition).map(transform).toList
No need to create the extra anonymous functions. foo = baz.\
list().\
filter{ bar => condition(bar) }.\
map(transform(_)).\
toList
IMO this is about as readable as it gets. It's like bullet points enumerating each step in the "algorithm" that produces a `foo`.AFAIK Javascript also uses this pattern a lot.
foo = baz
.list()
.filter{ bar => condition(bar) }
.map(transform(_))
.toList;Edit: and yes, that line separation works fine, both compiled and in the REPL.
2: When I hit `transform(bar)`, I don't know what `bar` is either. I have to jump forward to disambiguate again.
3: Once I hit `for bar in` I realize I'm in a comprehension, but that's still not enough to figure out what `transform(bar)` is acting on. I have to read to the end of the `if` condition, then backtrack to the beginning.
bonus reason: why not `list(baz)`? Is there actually some logic to when Python uses methods and when it uses global functions? If so, please tell me.
another bonus reason: when I was learning Python, I found the keyword reuse genuinely confusing. I would try to write for loops like `for x in my_list if condition(x):` and couldn't figure out why it didn't work because I knew I had seen that syntax somewhere before.
Now, your particular example isn't that bad, but if you make it just a little more complicated you get something like this aberration:
foo = [transform(bar) if bar.property else bar for bar in baz.list() if condition(bar)]
Nothing will convince me that you're not a mutant if you think that's clear and concise.Meanwhile, over in Ruby-land, we write this:
baz.each.select{ |bar|
condition(bar)
}.map{ |bar|
bar.property ? transform(bar) : bar
}
Which to me parses very easily into meat-brain logic, in small chunks, with a single pass:-Start with `baz`
-Consider each item
-Select only those `bar`s that meet `condition`
-Map each `bar` to...
-`transform(bar)` when `property` is true; itself otherwise (okay, natural language actually more closely resembles Python-style ternaries here. Sue me).
P.S. apologies for the multiple edits; I am an HN formatting noob.
All research I have seen says that proficient readers of a language read closer to a line at a time than a token at a time, so I suspect that not really a problem so much as a rationalization of aesthetic preference.
> bonus reason: why not `list(baz)`? Is there actually some logic to when Python uses methods and when it uses global functions?
list is a built-in type, and (as is usually the case for Python types) list() is the type constructor. There are other global functions in Python and there is room for debate over whether they make sense over methods, but constructors for built-types are pretty clear.
baz.list() is a method on baz. Assuming baz is iterable, list(baz) is valid, it's just different than baz.list().
foo = [transform(bar) for bar in baz.list()]
Adding an if condition looks like this: foo = [transform(bar) for bar in baz.list() if condition(bar)]
But an if/else expression looks like this: foo = [if condition(bar) transform(bar) else other_transform(bar) for bar in baz.list()]
Adding an else requires completely rewriting the line! Super ugly and inconsistent.Edit: formatting... don't know why my the 'list()' in my last example is disappearing
foo = [
if condition(bar) transform(bar) else other_transform(bar) # 1: storage
for bar in base.list() # 2: iteration
if bar_tester(bar). # 3: filtering
]
to each his own I suppose, until the PEP8 police come and get us all!!!I think this would be easier to read, given that what's inside the [] now looks almost exactly like the equivalent code without using a list comprehension:
foo = [for bar in baz.list() if condition(bar) transform(bar)]
(Disclaimer: I am not a regular Python user. Maybe that ordering conflicts with a syntax for something else.)