It’s not often that a popular news source will cover a feud between two poets. But in 2012, The Guardian did just that. After Carol Ann Duffy (the UK’s poet laureate) claimed that poetry, in its brevity, “… is a form of texting”, Geoffrey Hill, then the Professor of Poetry at Oxford, responded virulently. In a lecture he gave at Oxford (which I was actually there for), Hill said:

As the laureate says, poetry is condensed. Text is not condensed, it is truncated. What is more it is normally an affectation of brevity; to express “to” as “2” and “you” as “u” intensifies nothing.

Hill’s point, that there is a meaningful difference between “condensed” and “truncated” text, I think can apply meaningfully to code clarity as well. That’s what I’m going to take a look at in this blog post. When is a shorter way of writing code worse, and when is it better, than writing it out a longer way? To illustrate the difference, we’ll look at two examples of condensing code from two different programming languags: JavaScript’s ternary operators and Python’s list comprehensions.

Let’s start with ternary operators. In JavaScript, rather than writing out an if/else block, you can express the same thing in a single line.

So, if you had some logic like,

if (condition) {
    expr1
} else {
    expr2
}

you could condense it into

condition ? expr1 : expr2

The code in the one-line version is certainly shorter. It even looks a little cleaner, devoid of the excessive parentheses and curly braces that makes JavaScript feel so unwieldily.

Let’s compare it to Python’s list comprehensions. List comprehensions are useful for making lists from other lists. So say we had a list of numbers, called numbers. If we wanted the squares of all the even numbers in the list, we might write a for-loop to get them:

even_squares = []
for x in numbers:
    if is_even(x):
        even_squares.append(x**2)

Here’s how we’d get that same list with a list comprehension:

even_squares = [x ** 2 for x in numbers if is_even(x)]

Like ternary operators, this shorter version looks a lot cleaner than the longer alternative. But as we look a little more closely, we notice the differences between these two modes of abbreviaton. In my mind, there’s no essential difference, in JavaScript, between a ternary operator and an if/else statement. In fact, when I see a ternary operator, I always have to translate it in my head. I have to remember what the question mark and colon mean, and I usually say something to myself like, “if the condition evaluates to true, then execute the first expression, otherwise execute the second expression”. By the time I’ve thought it through, I’ve translated the ternary operation into its equivalent if/else statement. While

condition ? expr1 : expr2

might be written on the page, in order to make sense of it, I have to mentally convert it to its expanded form:

if (condition) {
    expr1
} else {
    expr2
}

While the longer form takes up more space on the page, it conserves mental energy, which is the far more precious resource.

Python’s list comprehension, on the other hand, actually reduces the amount of thinking I have to do in order to understand what it’s doing. A list comprehension describes the data you want better than a for loop can. There’s an easy mental translation between: “a list of the squares of even numbers in a list of numbers” and something like

[x ** 2 for x in numbers if is_even(x)]

Writing this out in the for loop doesn’t describe what the data is; rather, it describes how to construct the data. It’s the difference, at a restaurant, between just asking for blueberry pancakes and asking the waiter to instruct the chef to mix up a batter, add blueberries, and cook them on a hot skillet, flipping until each side is golden. How you make the pancakes is beside the point, all you care about is getting them eventually on the plate in front of you.

When I was first learning to program, I saw a lot of bad code, only I didn’t know it at the time. I thought weird syntaxes, poorly named variables, and functions with thousands of lines in them were normal, even a sign of expertise. They’re not. Programming languages, like human languages, allow a whole range of expressive flexibility. But also, like human language, there are implicit rules that dictate clear expression. Ternary operators are just jargon. They obfuscate meaning.

But list comprehensions in Python are off-putting in their own ways, too. I think one of the reasons I found them so clear is that they look a lot like sets, which I was already familiar with from math classes I took in college. (It turns out that sets were actually the explicit inspiration for list comprehensions, something I learned after starting to write this post.) In math, if we wanted reason about all the even squares, we’d write something like

{x2 | x ∈ ℕ, x is even}.

You’d say that out loud something like, “the set of squares of x, for x in the natural numbers, if x is even”.

I never thought I’d end up programming, so it was just lucky that I had previously studied — and spent considerable time adjusting to — the vocabulary of set theory. I’m guessing that list comprehensions aren’t as straightforward if you happened not to have that background.

Nevertheless, I still think that’s worth the mental effort to wrap your mind around list comprehensions. The difficulty in understanding list comprehensions is conceptual. Once the concept behind them is clear, their syntax mirrors the way you’ll natually think about making collections from other collections. In contrast, ternary operators are difficult because they’re a secret code that you need to decipher each time you read them. They work against you. There’s no deeper understanding reflected in their syntax. As Hill might put it, nothing’s intensified.