Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Nim supports both qualified and unqualified imports[0]. One uses `from module_name import nil`. Then every access to members of that module must be qualified.

From my viewpoint (I'm sure there are others) I see two main reasons why unqualified imports are the default: operators and templates/generics.

First, operators[1]. In Nim, one can implement an operator for any type, without extending that type, and without even implementing the operator in the same module as the type definition. If qualified imports were the default, then

  a + b
would by default be

  module_name.`+`(a, b)
(The backticks are used to force the plus sign to be recognized as an identifier)

Yes, one could hypothetically perform an "unqualified import" for that specific symbol, but what if you have 5+ operators to import (like for a math library)? It would get tedious rather quickly.

Now, templates. If you're not familiar with Nim, templates are similar to C templates, except that rather than a template performing textual substitution, it performs syntax tree substitution. As an example, this is how "less than" is implemented:

  template `>`*(x, y: untyped): untyped =
    ## "is greater" operator. This is the same as ``y < x``.
    y < x
If qualified imports were the default, templates would be almost useless. Something like this:

  template toJsonString(value: untyped): untyped =
    $(toJson(value))
where `$` turns its argument into a string, and toJson turns its argument into a JSON node type, would fail because the template doesn't qualify any of those procedures.

The same reasoning for templates also applies to generics (and might be a bit more familiar). A generic doesn't know where its input type comes from ahead of time, so it can't know how to qualify function calls.

Python, C#, and other class based languages deal with these complications by using classes as a kind of "automatic unqualified import" signal. Though it doesn't have classes, Go uses a similar mechanism (explicit methods types that must be defined in the same package as the type implementation). Since Nim has neither method types nor classes, it just uses unqualified imports.

I agree that unqualified imports are a pain for code navigation, but with the right tooling that navigation can be made easier (I know there's a Nim plugin for VSCode, and I believe there's ones for Vim and Emacs?)

[0] https://nim-lang.org/docs/manual.html#modules-from-import-st...

[1] https://nim-lang.org/docs/manual.html#syntax

[2] https://nim-lang.org/docs/manual.html#templates



Operators are an argument for why it should be opt-in. Most code you write doesn't use imported operators, and when you do use them, you aren't using many of them. Encumbering everyone's code for code that they might write isn't usually the right trade-off.

Just make provide the feature via opt-in. Other languages do this just fine:

    from Lib import (foo, (+)) // Just +
    from Lib import (foo, (...)) // All operators
Good defaults are important so that the ecosystem develops good conventions. Else you get "well, you can qualify imports if you want" as seen in this thread. After reading code all weekend, nobody qualifies imports in Nim.

And I also believe in escape latches, not absolutism. If your templating argument were the best reasoning, then it makes sense for that to be an isolated idiosyncrasy rather than a reason for all code to pay the penalty of unqualified imports by default.

Just like you can opt-in to importing entire namespaces into scope in other languages, but you only do it on occasion when it makes sense, not by default.

Anyways, I know this is classic HN bikeshedding, but Nim gets mentioned a lot on HN, the developer clearly has a good eye for attention to detail and thoughtfulness. So it surprised me that Nim had what I consider one of the fundamental mistakes in programming languages along with, say, a lack of first class Optional<T>.


What is the perceived penalty of unqualified imports in Nim specifically? The only one that seems valid is you can't immediately see the module a proc is defined in, but you can opt in as you say with module qualifiers if you want to.

None of the "namespace pollution" stuff applies to Nim since ambiguity is a compile time error and there's no performance penalty for having everything imported as Nim uses dead path elimination.


It's true that custom operators aren't implemented very often, but what about templates and generics? Both are used quite frequently.


I'm not convinced unqualified imports are necessary or helpful for generics. Zig has generics just fine without unqualified imports.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: