One of many things I love about Python is how whitespace is an integral part of the language. Python was the first popular programming language designed with the idea that “code is read much more often than it is written.” Forcing authors to indent code in a maintainable fashion seemed a brilliant idea when I first encountered Python fifteen years ago. The lack of braces scattered throughout the code made for easier reading. Somewhat ironically, it also makes the language easier to write: Typing the brace character requires a certain amount of finger gymnastics.

But that was then. Editors have changed in the intervening years. People have been arguing about code style for as long as they’ve been coding. When I started coding, each programmer had a different style, and we tended to mouth off about really stupid things like whether a function’s opening brace should appear on the same line as the definition or the next. Seriously, there were actual debates about the preference between these two basic C functions:

void main() {
    printf("hello world");
}

and

void main()
{
    printf("hello world");
}

Different companies and projects had extensive documentation about coding style. Code review, when it happened, devolved into pointless discussions of style instead of useful logic improvements.

Python created the famous language-wide style guide known as pep8. The hope was that the Python community would settle on one style and people wouldn’t spend as much time learning new rules when they changed companies. Anyone could hack on anyone else’s open source code without becoming perplexed by stylistic differences.

Pep8 isn’t perfect and allows for a lot of variation. Over time, automatic formatters were introduced that would make your code more consistent without having to think about it. Newer languages like Go and Rust even ship with default formatters, precluding stylistic arguments before the language even gains adoption.

Python has its own collection of code formatters, but I’m only going to link to black because it’s the only one that follows the zen of python philosophy “There should be one– and preferably only one –obvious way to do it”. It eliminates most debates, other than the line-length argument that has already collectively wasted decades of person-hours.

Black is amazing. But not as amazing as rustfmt or js-beautify. This isn’t a limitation in black, it’s a limitation of Python. Black is not able to adjust indentation for me because indentation is part of program structure. Consider the common case of moving a line into a conditional. Imagine I have this:

def my_function(x):
    if x > 5:
        print("something happened")
    else:
        print("nothing happened")

    print("I decided this shouldn't always happen")

As indicated, I now decide I want to move the last line inside the “else” clause. Assuming my cursor is on the line I want to move, the keystrokes for this in vscode are alt-up, ctrl-} and ctrl-s. The first moves the line up, the second changes the indentation, the last, of course, saves the file, which forces my formatter to run. Now I have this:

def my_function(x):
    if x > 5:
        print("something happened")
    else:
        print("nothing happened")
        print("I decided this shouldn't always happen")

But if I do the same in Javascript, changing

function my_function(x) {
  if (x > 5) {
    console.log("something happened");
  } else {
    console.log("nothing happened");
  }
  console.log("I decided this shouldn't always happen");
}

to

function my_function(x) {
  if (x > 5) {
    console.log("something happened");
  } else {
    console.log("nothing happened");
    console.log("I decided this shouldn't always happen");
  }
}

the sequence of keystrokes is alt-up, ctrl-s.

This saves me a ctrl, a shift, and a }. Three keystrokes isn’t a huge saving; Some might argue “well, all the little savings added up over the course of a day are probably worth something”. The truth is, typing more efficiently, as a linear-complexity improvement, is nothing compared to the ploynomial time spent staring off into space figuring out how to solve your problem. It will never recover time spent trying to find editor plugins or learn keyboard shortcuts that might save a few keystrokes here and there. Truthfully, I do this all the time because it’s fun, but there’s no way I could justify the time invested!

The real benefit is that I no longer have to think about “program style”. I just type valid code and let the formatter take care of it. This relieves a cognitive burden I never knew I had, and allows me to code effectively for longer periods between those “staring into space” pauses. But with Python, indentation is an integral part of my program. It isn’t “program style”, it’s “program structure”. So black is unable to remove that bit of overhead from my workflow. It seems like a small thing, but I’ve been switching between Rust, Python, and Javascript, and I’m actually noticing the overhead when I code Python.

It’s interesting how language features can limit editor support. There are other ways this is true as well; Python’s intense dynamism makes it tricky for editors to implement autocomplete or “jump to definition” type features, for example. Python is the best language to read and write using an editor with no language support, like a whiteboard, but it doesn’t lend itself to modern code aid features.

In contrast, a language like Java is frustrating to write without extensive editor support. It’s verbose and difficult to navigate numerous files. However, if you use a great Java IDE, it can be an enjoyable experience. You never have to stop to look up documentation or method names, the code is formatted nicely, just type and let it go.

Language features influence how well an editor can support that language. Should the converse also be true? I find this a fascinating question.

In the 90s, companies like Borland and Microsoft developed languages and editors side-by-side. Visual Basic, the language, was rarely coded without the accompanying Visual Basic, the IDE. Through the 2000s, when Java was most popular, a ton of effort went into developing various competing IDEs to support the language. More recently, as Python and Javascript have dominated the landscape, people tend to prefer lighter-weight coding editors such as Sublime, Atom, and VSCode.

Now, Python (and Javascript variants) has introduced gradual typing, which helps an editor provide autocomplete and code navigation. Newer statically typed languages, like Rust and Go, on the other hand, have strongly emphasized type inferencing (as have recent iterations on C++ and Javas). Type inferencing does not help with editor support, but it does make the language easier to read (sometimes) and write. Python recently introduced the breakpoint() built-in, which helps editors implement custom debuggers. Javascript has had the debugger keyword for a good while. Such a feature has absolutely no purpose in terms of compiling/interpreting the language or communicating with other source developers; it’s only useful with external tools that support it.

It’s not like the code editors are going away. As long as we are coding, we’ll need ways to write code. I think iterating on language design to make languages easier to edit using the latest tools is a good thing. With core python developers working full time for the VSCode Python team, I expect to see more of this in the Python language, and others will likely follow suit.