The Python version uses intermediate variables so the author of the code is to blame for verbosity, not the language.
The Python version uses intermediate variables so the author of the code is to blame for verbosity, not the language.
I think I wrote a script I needed in Rye and I found it interesting, then I went to Fiver and paid someone to write a script in Python that does the same.
2021 were different times, and I hope I've grown a little too... and now I would ask ChatGPT or Gemini :)
The code examples are a tad too verbose but actually better quality than most real-world Python codebases, I would say.
Python is not very verbose but it's not very concise either (especially compared to Lisp families)
Variables also help readability, because the name can help you discern what those functions return.
But using long chains of expressions is the same as one-liners or point-free style in Haskell. It saves some typing and also you can skim the code more easily, but only if you're extremely familiar with what's going on there.
I wonder how much you can benefit from this, if you return to the codebase after a 6-month break though. Maybe some people do manage to really memorise these details, but for some of us the effect is more like "wtf is this code doing?"
I prefer more verbs and not too many nouns, and I think our brain is used to reading "sentences" like that.
get http://example.com |parse-html |find-links |for-each { .if-external { .print-it } }
Is not that dissimilar from instruction we can understand quite well: Take a basket, look into it, pick out apples, if the apple is red take it.
If there are complex procedures, I also want to name a temporary result. It's like a divide and conquer strategy. You divide complex expression or instructions to separate definitions and combine those. But I also don't want to divide too much. This on the other hand again obscures IMO.If I name every internal state, we get this.
hmtlStr = get("http://example.com)
html = parse(htmlStr)
links = findLinks(html)
for l in links {
take = isExternal(l)
if take {
print(l)
}
}
Which I can parse, but it takes more energy to validate that I used the right variable at the right place, not some variable from higher up in the code for example. You probably also don't code like this, but there is some middle ground ...Just as a thought experiment, don't take me too seriously I will try to "humanize" those instructions:
Take a basket in your hands.
Look into the basket in your hands.
Find apples in looked basket in your hands.
For every apple.
Check if the apple is red.
If it's red, take the apple.
Maybe you can make more balanced version which will be the best of both worlds. Thanks for the discussion :).It's funny, because I'm watching my experience as I'm reading the code and I feel like variables are like a little break while doing work. When you don't use them, it feels like a constant run.
Also, they give some extra structure, because they name the output of the function. It's true that you have to make extra effort to think of the name, though.
I'll be honest, your example with naming every internal state feels comfortable. Sometimes I do chain a few expressions together, but I avoid chains that are too long. I want to say that more than 3 is too much, but maybe it depends on the specific code.
I don't have examples of my own code handy, so I can see how I did it in the past. Now that I think about it a bit more, I think I'm okay with a longer chain, if it involves transformations of the same structure, but not if it involves destructuring. I perceive the `for` loop as a destructuring.
let rms = sqrt . sum . map (^^ 2)