Unqualified imports might be more readable than qualified imports. But unqualified imports are more trouble than qualified imports. Readability should not be confused with clarity. The trouble is that unqualified imports are unclear.
I’m debugging some Elm code that I didn’t write.
The file is 649 lines because large files are encouraged.1
I arrive at line 475 where an unfamiliar function is called.
I want to know what the function does.
Now I must jump to the top of the file and hunt for this function name among
the import declarations.
There are sixteen import declarations.
Three declarations use this form:
import Foo exposing (..).
So I must look for the function in all three libraries, hoping I find it in the
In the end, I’ve forgotten what I was doing on line 475.
The fallacy of the unqualified import is that small, simple names are more “readable”. Here is an example from the popular Elm library NoRedInk/elm-decode-pipeline.
This is meant to be code that reads like a plain-English description of what it
The code is considered readable because I can scan these lines and understand
User is required to have an id and an email address but not a name.
hardcoded are composed like words
into sentences that describe the underlying domain model.
Qualified imports ruin the effect.
What was once Elm poetry is now just Elm code.
I am gratified by the poetry when I don’t need to deeply understand the
But if I need to know about
string, I am easily confused.
I might guess that those functions are exported by
In fact, they are not.
Those functions belong to
And these libraries are commonly used in the same context.
Without qualified imports, I am constantly jumping to the import declarations or
guessing about where to look for documentation.
Maybe readability can be preserved and confusion mitigated by using an import alias.
This compromise might appeal to the developer who is enamored with small, simple function names. I am doubtful that this compromise means less jumping to the top of a file. The code is clarified by the alias only when I have memorized every alias in the file. And that clarity lasts only as long as I can maintain the memorization.
Aliased module imports breed their own trouble.
What if someone chooses an odd alias?
Humans are not dependably clear thinkers.
People inexplicably call a
And what if two modules are reasonably referred to by the same alias?
Foo might be
So I’m still jumping to the import declarations like a dog rummaging through
dead leaves looking for a chicken bone.
Traversing the file is not hard. My hand mostly remembers to set a mark before making the jump.2 Marks make the round trip between call site and import declaration pretty quick. So I am not trying to save myself key strokes. I am trying to save myself from thinking.
I don’t want to think about “where does this function come from?”.
I don’t want to think about “does
I don’t want to think about a reasonable alias for
I just want to know immediately where this unfamiliar function comes from so
that I can get on with my work.
The full module name, however long, is the only name guaranteed to give me
I have recently conceded that qualified and unqualified imports are both appropriate, depending on the context. I conceded this to end an argument that was lasting too long. Privately, I remain a qualified import absolutist.
Rules are useful to the degree that they can be applied consistently. “Always qualify imports with the full module name” is a useful rule because it can be followed consistently. “Depending on the context” is not a useful rule because it invokes a personal judgment, the result of which is not dependably consistent.
What is gained by inviting the spectre of the subjective when it can be avoided? Why must code be self-expressive one degree more than it necessarily is?