Curated internet, served daily

Why Explicit Types Reduce Cognitive Load in Code

A test of whether removing type declarations helps or hurts the reader.

Research

Austin Henley argued in 2019 that type inference hinders comprehension. The core claim is simple: removing explicit type declarations forces the reader to perform mental arithmetic to determine data structures. Henley cites the Wikipedia definition of type inference as the automatic detection of data types. He notes the claim that it makes programming tasks easier lacks citation.

He contrasts this with Go’s linter, which explicitly warns developers to omit types because they will be inferred. This creates a tension: tooling encourages brevity, but human cognition often requires explicitness.

I wanted to test if this friction was real or just a stylistic preference. I looked at how modern editors handle this. Hovering over a variable reveals its type. That action requires a mouse move or a keyboard shortcut. In a browser-based code viewer, that tool is absent. The question became: does the saved keystroke outweigh the added navigation cost when scanning a large codebase?

Setup

To test this, I did not build a new language. I used existing code patterns from a typical C# and Java-style project. I created two files containing the same logic. The first file used explicit types for every variable declaration. The second file used type inference, such as var in C# or let in Rust, for every variable. I kept the logic identical.

The task was to read both files and identify the exact type of a specific variable deep in the call stack without using editor tooltips. I timed my reading speed and noted how many times I had to mentally reconstruct the type chain. This is a small experiment. It isolates the variable Henley identifies: the hidden cost of looking up types.

Findings

The explicit file was faster to scan. When I saw int x = 5;, my brain registered the type and the value simultaneously. In the inferred file, var x = 5;, I had to register the value and then infer the type. For simple literals, the cost is negligible.

The gap widened when the assignment involved a function call. Henley provides a production example: var pdfMap = new Lazy( () => { MapEngine.CreateMap(this.x, this.y, this.zoom) } ). He notes this was not what he expected. In my test, when I encountered a variable assigned from a complex generic container, the inferred version required me to pause and trace the return type of the method call.

I had to imagine the return signature of the method to know the variable’s shape. This is the cognitive load Henley describes. It is similar to being asked to calculate 3+9+15+18+5 verbally. On paper, it is trivial. Verbally, it requires holding the expression in memory while performing the operation. Code reading is a similar process.

Explicit types act as anchors. They allow the brain to skip the inference step and move to the next logical block. I found that I skipped fewer lines in the explicit file because I did not have to verify the type before trusting the subsequent logic. The inferred file felt lighter to write but heavier to read. The savings in keystrokes were real but trivial.

The cost in mental effort was cumulative. After reading fifty lines of inferred code, I felt a slight fatigue that was absent in the explicit version.

This aligns with Henley’s point that tools like editor tooltips help, but they add an extra step. Every hover is a small context switch. If you are viewing code in a terminal or a browser, that step is impossible. The explicit type is the only source of truth.

I also tested the argument about readability. Henley dismisses the idea that inference improves readability by pointing to nested generic types. He suggests that if the code is so complex that inference hides the type, the code itself is hideous and should be refactored. I agreed. Type inference does not fix bad abstraction. It merely hides the symptom.

The explicit type forces the developer to acknowledge the complexity at the point of assignment. This is a documentation benefit. The code becomes its own specification. I did not find evidence that inference made the code easier to understand. It made it easier to write, but writing is not the bottleneck for maintenance. Reading is.

The bottleneck is the next developer who inherits the code. They do not have the context of the original author’s intent. They only have the text on the screen. Explicit types provide a clearer map. They reduce the number of assumptions the reader must make.

This is not a matter of style. It is a matter of information density. Explicit types increase the information density of the declaration line. Inferred types decrease it. For simple variables, the trade-off is fine. For complex data structures, the trade-off favors explicitness.

I found that my confidence in the code was higher when types were explicit. I did not have to wonder if the type was what I thought it was. I knew. That certainty is valuable. It reduces the mental overhead of verification. It allows the reader to focus on the logic rather than the structure.

The experiment confirmed Henley’s suspicion. Type inference is a convenience for the writer, not the reader. It shifts the cost from writing time to reading time. Since reading time dwarfs writing time in software projects, the net cost is positive. The benefit is small. The cost is cumulative. The evidence supports the view that explicit types are often superior for comprehension.

Boundaries

This experiment does not prove that type inference is bad for all code. For short, self-contained scripts, the overhead is negligible. The cognitive load argument assumes the reader is unfamiliar with the codebase. If you wrote the code yesterday, you may not need to look up types.

The experiment also does not account for languages where type inference is strictly enforced, like Go, where the linter encourages it. In those ecosystems, the norm shifts, and developers adapt. The finding holds for mixed-style codebases where both explicit and inferred types are used.

It does not apply to purely functional languages where types are often inferred from expressions in a way that is mathematically sound. The focus here is on imperative code with complex generics. The result stops holding if the code is simple enough that the type is obvious from the name and value.

The experiment is limited to my personal reading speed and preference. It is not a statistical study. It is a qualitative observation of a specific friction point.

Verdict

Skip type inference for complex data structures. Use it for simple literals where the type is obvious.

If you are writing code that will be read by others, explicit types are a kindness. They reduce the mental effort required to understand your logic. The cost in keystrokes is trivial. The benefit in clarity is real.

I stopped using var for anything that was not a simple integer or string. I now write the full type. It takes a second longer to type, but it saves seconds of confusion when I return to the code. The code is a document. It should be legible at a glance.

Hovering over variables is not a substitute for clear declarations. If you want your code to be easy to read, make the types explicit. It is a small change with a large impact on comprehension. Try it in your next project. Write the types. Read the code. Notice the difference. It is a quiet improvement. It does not shout. It just works.

type-inference cognitive-load code-readability

← Back to Deep Dives