August 1st, 2024

The human typewriter, or why optimizing for typing is short-sighted

The article highlights the drawbacks of optimizing code for typing speed, advocating for readability and clarity over efficiency, as obfuscated code increases mental strain and confusion among developers.

Read original articleLink Icon
The human typewriter, or why optimizing for typing is short-sighted

The article discusses the drawbacks of optimizing code for typing speed, particularly through the use of auto and template type deduction. The author, Felix Klinge, argues that such practices can obfuscate code, making it harder to read and navigate, which ultimately increases the mental strain on developers. He emphasizes that code should be optimized for readability and ease of debugging rather than for typing efficiency. Klinge provides a code example to illustrate his point, showing how the use of auto types can lead to confusion about variable types and their implications. He contrasts this with a rewritten version of the code that clarifies types and improves understanding. The author encourages developers to consider the perspective of others who may read their code, advocating for clarity and explicitness in programming practices.

- Optimizing for typing speed can lead to obfuscated code.

- Readability and ease of debugging should be prioritized in coding practices.

- The use of auto types can create confusion about variable types and their usage.

- Clear and explicit code improves understanding for all developers.

- Developers should consider the perspective of others when writing code.

Related

Optimizing JavaScript for Fun and for Profit

Optimizing JavaScript for Fun and for Profit

Optimizing JavaScript code for performance involves benchmarking, avoiding unnecessary work, string comparisons, and diverse object shapes. JavaScript engines optimize based on object shapes, impacting array/object methods and indirection. Creating objects with the same shape improves optimization, cautioning against slower functional programming methods. Costs of indirection like proxy objects and function calls affect performance. Code examples and benchmarks demonstrate optimization variances.

Why We Build Simple Software

Why We Build Simple Software

Simplicity in software development, likened to a Toyota Corolla's reliability, is crucial. Emphasizing straightforward tools and reducing complexity enhances reliability. Prioritizing simplicity over unnecessary features offers better value and reliability.

Beyond Clean Code

Beyond Clean Code

The article explores software optimization and "clean code," emphasizing readability versus performance. It critiques the belief that clean code equals bad code, highlighting the balance needed in software development.

Clang vs. Clang

Clang vs. Clang

The blog post critiques compiler optimizations in Clang, arguing they often introduce bugs and security vulnerabilities, diminish performance gains, and create timing channels, urging a reevaluation of current practices.

How I Program in 2024

How I Program in 2024

Kartik Agaram reflects on his programming journey, advocating for minimalist software design, emphasizing simplicity, context awareness, and the potential benefits of data-oriented design to improve software quality and adaptability.

Link Icon 16 comments
By @Animats - 4 months
This is something that seems to be settling down in language design. Local variables are usually implicitly typed, and function parameters are usually explicitly typed. This is for readability. "auto" was retrofitted to C/C++ so those languages have implicit typing of locals. C# and Java added "var". Rust uses "let". So this is now pretty standard.

Type info is needed on function signatures mostly so people know how to call the thing. That's why Javascript and Python have acquired bolt-on typing systems. It's also why cross-function type inference hasn't caught on. It can be done technically, but it just confuses the humans.

Humans are not good at maintaining consistency between the thing right here and that other thing way over there. It's best not to design systems which require that.

By @lawn - 4 months
> auto lovers will say that the IDE will resolve the types for you if you really care, but would someone please think of our poor Vim & Emacs users?

This poor Neovim user also has LSP with inline hints, hover and help like IDEs.

Vim/Emacs aren't just the dumb text editors anymore.

By @redsaz - 4 months
> This post can definitely be considered a “religious” opinion piece

The author certainly has that right, because the post steps on two programming religion landmines, from how I read it:

1. strict static typing (without type inference) is good. 2. code should be written to allow IDEs to enhance navigability, rather than written on the assumption that IDEs will be the sole provider for navigability.

I believe there is a point to be made in the "when we don't know what we're getting back, that harms navigability" camp. But as another commenter posted, there's a point to be made in the "when we overspecify what we're getting back every time, that can harm readability, too" camp.

I can't express where this balance is. It's somewhere between poetry and a legal document, the prose where you can really get into a good book and enjoy the world that the author presents. Some people really like the beauty of a short poem. Other people may require precise wording that leaves no room for enjoyment or interpretation. The rest of us can have the majority of fun somewhere in between.

Where that "in between" equivalent would be in my day-to-day programming, I'm not entirely sure, because what I'm writing could be a short script where brevity is vital (poetry-ish) vs some section of unfortunately highly complex code with lots of tests for edge cases (legalese), and all the other code where I'm still world-building and conveying ideas (prose). And I believe that complexity should be spelt out as precisely as it can in the code itself, rather than rely on the hope that somebody else is using the same IDEs and features as me. I've tried using type inference where it seems fine to use, and then spelling out the exact type that a variable wants where it isn't clear what might get returned, all in the same app, but it comes across as sloppily inconsistent in my mind. Ah well.

By @jbandela1 - 4 months
The code presented has problems, but they are not the problems the author thinks it is.

The code is listed as c++. However, it is using a style that will result in problems.

First thing that jumped out at me is using const char* for strings. Using this muddies ownership and doesn’t store the length of the buffer which can result in all sorts of fun. Add to that that many times paths are formed by string concatenation, and it is looking like a code smell.

Second, there is no RAII and just manual management of resources.

These problems are far more likely to cause issues that the use of type deduction which by now has pretty good tooling support and is used successfully in many languages. Of course, not using RAII, using raw pointers make it tricky, but you shouldn’t be using those like that anyway.

By @lifthrasiir - 4 months
The article starts with a correct problem statement and concludes with a weird claim, because nowadays IDEs like Visual Studio Code do support the best of both worlds: inlay hints. I turn them off by default on VSCode (because it messes with columns, unfortunately) but configured them to `offUnlessPressed` so that I can quickly check inlay hints by pressing Ctrl+Alt/Option.
By @Sytten - 4 months
Rust and Kotlin would like a word. What a weird take. All editors now have LSP support now and your editor/compiler should definitely figure this out for you.
By @huijzer - 4 months
Although there are inline hints, I agree with you that auto makes readability worse. Especially in situations like PRs and Git forges where inline hints are not always available.

LLVM has a well thought out stance on auto too: https://llvm.org/docs/CodingStandards.html#id29

By @boxed - 4 months
It's funny reading this coming from Python where I code without types and it's perfectly fine.

That being said, there is a third option here:

- type `auto`

- have an autoformatter that replaces `auto` with `std::vector<std::string>::iterator` or whatever the abomination of a type you need is :P

By @hkrpnc - 4 months
The author uses a code snippet that looks like the average Python code:

Untyped, non-descriptive objects calling each other randomly, with no chance for the reader to figure out what is going on.

So in this case auto is harmful. In many other cases it isn't.

By @atoav - 4 months
Using one letter variables and the such is excusable if you are new to programming and don't know better or if you use it in such a local context that the short length helps readability or if it is a "known" short variable like i or some sort of speaking short variable like db.

I like to think of myself as a good programmer, but whenever I encounter code where I have to figure out what "x" means, when it could have been a speaking variable like "accumulative_duration_ms" I feel like someone is trying to be clever.

I see using auto in a similar light. Explicit return types are good. In fact there's a trend to retrofit typing into languages that don't have it. You showing me that you value not thinking about the return type over specifying explicit return types is a red flag to me.

If we as programmers should value anything, it is the time and mental resources of the person who has to read our code in the future — very often that person is going to be you, yourself.

By @nottorp - 4 months
To add to the original article's point, even the IDEs are optimized for typing. Think how they auto complete { and " and other stuff that comes in pairs for you. Great when you crank out new code, can be maddening when you're editing.
By @BugsJustFindMe - 4 months
The rules are simple:

Use auto when the local code shouldn't care about the type as a way of signifying that the local code shouldn't care about the type. It doesn't happen all the time, but it does happen sometimes.

Don't use auto when the code needs to care about the type.

By @MeteorMarc - 4 months
Optimizing for navigation is an interesting notion. Lack of navigation is also my main problem with class hierarchies. Importing a class is like import *: you do not see anymore in the module itself where some method is defined.
By @qnleigh - 4 months
> but would someone please think of our poor Vim & Emacs users?

This comment is sort of ironic given the title of the piece. As a Vim user, I opened it expecting to be called out for optimizing for typing.

By @diffuse_l - 4 months
My take is that auto primary advantage isn't optimizing for typing, it's optimizing for refactoring.
By @dureuill - 4 months
Very disappointing read.

Starts with an interesting claim "don't optimize for typing", but then it completely fails to prove it, and confuses itself in thinking that `auto` is an optimization for typing.

`auto` is:

- A way to express types that are impossible or truly difficult to express, such as iterators, lambdas, etc

- A way to optimize reading, by limiting the redundancy

- A way to optimize maintenance, by limiting the amount of change brought by a refactor

The insistence on notepad or "dumb editors" is also difficult to grasp. I expect people reviewing my code to be professionally equipped.

Lastly the example mostly fails to demonstrate the point.

- There's a point made on naming (distinct from `auto`): absent a wrapping type, `dataSizeInBytes` is better than `dataSize`. The best way though is to have `dataSize` be a `Bytes` type that supports conversion at its boundaries (can be initialized from bytes, MB, etc)

- What's the gain between:

    auto dataSet = pDatabase->readData(queryResult.getValue());
and

    DatabaseDataSet dataSet = pDatabase->readData(queryResult.getValue());
The `dataset` part can be inferred from the naming of the variable, it is useless to repeat it. The `Dabatase` is also clear from the fact that we read data from a db. Also, knowing the variable has this specific type brings me absolutely nothing.

- Their point about mutability of the db data confused me, as it is not clear to me if I can modify a "shadow copy" (I suppose not?). I suggest they use a programming language where mutating something you should not it a compile time error, it is much more failsafe than naming (which is hard)

I'm sad, because indeed one shouldn't blindly optimize for typing, and I frequently find myself wondering when people tell me C++ is faster to write than Rust, when I (and others) empirically measured that completing a task, which is the interesting measure IMO, is twice as fast in the latter than in the former.

So I would have loved a defence of why more typing does not equate higher productivity. But this ain't it.