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

> Not OP, but they are referring to `import std/strformat` (from homepage).

> That just imported things into the global namespace.

That's what tripped me up: there's definitely no such thing as importing into GLOBAL namespace. That's an import into a top-level (true) namespace of a MODULE. In Python, if you put something into the dict returned from `globals()`, you are indeed importing into global namespace, but I've never seen it actually done. Anyway, that might seem like nitpicking, but it's an important distinction. [EDIT: C `#include`s are an example of actually importing into global namespace]

With that out of the way: the wildcard imports are frowned upon for a reason. What reason? Basically, it's hard to tell a) what identifiers were imported, b) if any of them are still used in the module (ie. if it's safe to remove the import). With multiple wildcard imports in one file you also get c) hard to tell where a given identifier comes from.

Now, none of these problems apply to Nim. Nim is statically typed. The compiler and the tooling knows exactly which identifier comes from where. If you delete all the places you used identifiers from a wildcard import, the compiler and the tooling will tell you that it's safe to delete the import. Another problem with wildcard imports is that the imported modules can change, leading to disasters like silently shadowing an identifier imported from somewhere else. Again, this cannot happen in Nim - it simply won't compile.

Every single linguistic feature has its pros and cons, but you have to remember to only weigh those in the particular context they're used in. What I mean is that wildcard imports in Python and Nim are very, very different beasts, and shouldn't be directly compared, if at all. It would make more sense to compare Nim to Elixir or Scala in this regard.

Note: obviously, Nim also has selective imports and whole module imports, too.



Cool thanks for the info.

Nim having selective imports solves any annoyances I would have.

But you mentioned all the reasons it was ok in Nim. But the answer is always that the compiler knows. That isn’t why I personally dislike this type of import. I dislike it as a user. I find it super annoying not knowing where an identifier is coming from.

I love having ‘fmt.Printf()’ instead of ‘Printf()’. Trivial example I know. I’m sure everything becomes fine once you are familiar with the ecosystem though.


There's a reason why wildcard/selective[1] imports are favored in Nim. It's because of the uniform function call syntax[2]. In short, this:

    split("a string", " ")
is exactly the same thing as this:

    "a string".split(" ")
`split` here is a normal function, not any kind of method. This means that you can chain normal functions as if they were methods on objects:

    "a string".split(" ").join("\n")
now, if you imported modules instead of functions themselves, how would that look like?

    sequtils.join(strutils.split("a string", " ") "\n")
or, if you wanted to keep uniform call syntax, you'd have to invent some new syntax:

    "a string".split<strutils>(" ").join<sequtils>("\n")
Which also doesn't look very appealing.

So, there are trade-offs here, and you obviously might not like the choices made by Nim, which is fine! But, there are reasons for the design decisions made by the language implementers, and they are almost never predicated on a single feature: all the features of a language interact with each other, sometimes in very strange and unpredictable ways. So it makes sense to consider the features your interested in the proper context :)

[1] `import modname` and `from modname import fun1, fun2`

[2] https://en.wikipedia.org/wiki/Uniform_Function_Call_Syntax


Great explanation, that makes total sense.

Thanks for giving the insight.


C++ somewhat solved this using Koenig lookup https://en.wikipedia.org/wiki/Argument-dependent_name_lookup




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

Search: