← Back to context

Comment by kbd

6 hours ago

The biggest thing I still don’t like about Nim is its imports:

    import std/errorcodes

    proc p(x: int) {.raises.} =
      if x < 0:
        raise ErrorCode.RangeError
      use x

I can’t stand that there’s no direct connection between the thing you import and the names that wind up in your namespace.

There is a direct connection, you just don't have to bother with typing it. Same as type inference, the types are still there, you just don't have to specify them. If you have a collision in name and declaration then the compiler requires you to specify which version you wanted. And with language inspection tools (like LSP or other editor integration) you can easily figure out where something comes from if you need to. Most of the time though I find it fairly obvious when programming in Nim where something comes from, in your example it's trivial to see that the error code comes from the errorcodes module.

Oh, and as someone else pointed out you can also just `from std/errorcodes import nil` and then you _have_ to specify where things come from.

  • When I was learning Nim and learned how imports work and that things stringify with a $ function that comes along with their types (since everything is splat imported) and $ is massively overloaded I went "oh that all makes sense and works together". The LSP can help figure it out. It still feels like it's in bad taste.

    It's similar to how Ruby (which also has "unstructured" imports) and Python are similar in a lot of ways yet make many opposite choices. I think a lot of Ruby's choices are "wrong" even though they fit together within the language.

100% my beef with it. same style as c++ where you never know where something comes from, when clangd starts throwing one of its fits

It needs to be this way so that UFCS works properly. Imagine if instead of "a,b".split(','), you had to write "a,b".(strutils.split)(',').

  • ok I do not understand.

    What is preventing this import std/errorcodes

    from allowing me to use: raise errorcodes.RangeError instead of what Nim has?

    or even why not even "import std/ErrorCodes" and having the plural in ErrorCodes.RangeError I wouldn't mind

    • Nothing, and it fact this works. To move to an example which actually compiles:

          import math
          
          echo fcNormal
          echo FloatClass.fcNormal
          echo math.fcNormal
          echo math.FloatClass.fcNormal
      

      All of these ways of identifying the `fcNormal` enum value works, with varying levels of specificity.

      If instead you do `from math import nil` only the latter two work.

Nim imports are great. I would hate to qualify everything. It feels so bureaucratic when going back to other languages. They never cause me issues and largely transparent. Best feature.

You are free to import nil and type the fully qualified name.

  • There are many things to like about Nim, but it does benefit from adherence to a style guide more than most languages.