There is no fine grained visibility control in Nim. (Because I found it a constant distraction in Java and C#. Bugs don't arise from visibility violations.)
Typically you export the fields other modules need.
Bugs don't arise from visibility violations.
Bugs arise from package clients using internal APIs that were not intended to be public but had to be exported to get around this language limitation, because
The fallout of this can include the package having to do awful things to preserve the functionality of this unintentionally-public API to avoid breaking some important client. (Yes, I have seen this happen. Mac OS and Windows system frameworks used to have multiple hacks to prop up apps like Photoshop and Office that were too important to break even though they were calling undocumented APIs.)
APIs are very important. They are a contract between the implementation and the client. They are the user interface of a library. Exposing internals in an API just because it seemed inconvenient to provide language features to hide them is bad design.
The Mac OS and Windows APIs are not written in Nim and offer an ABI, not just an API. And the undocumented APIs were used because there were no other better alternatives provided...
There is no proof whatsoever that a comment like "for internal use only, use public API X instead" doesn't suffice. You compare it to "for internal use only and we offer no alternative API".
And even if it does cause a bug every second full moon, you have to weight that against the constant development friction -- "should I use package level visibility? protected? private?" added on top of the other choices you have to make -- "which type to use for this? how to name this field?" and in Nim's case -- "which exceptions can this really raise? what other effects does it have? Can it access global varaibles? which of these parameters are immutable?"
This quickly adds up and you're in a land where everything is nailed down precisely when you write it. And everything is hard to change later on.
Interesting. We do have include as well as import. I guess there may be some situations where include causes trouble.
A user willing to take responsibility with the power like Spider-Man's Uncle Ben says could import[all] foo. That might not be so awful.
A link for those wanting it.
Personally, I think the qualifier "private" is a bit weird because it sounds like it might mean "import only the private parts" which naturally makes no sense, but then your brain has to adjust back to the sensible interpretation of "import privates/hidden/etc. also". It's also longer than "all". Hey..no one on the GH thread seemed to be bikeshedding this aspect. ;-)
I think import pragmas in general is a fine idea, though I agree cyclic imports are probably more important and incremental compilation (IC) before that.
Also, it did not seem to arise on the GH discussion, and I didn't see it at a glance in the PR, but it probably bears mention that multi-module imports probably all get the same treatment. import a, b {.all.} === import a {.all.}; import b {.all.}.
There is also the option of having a specific public API module that only exposes what you want to expose. This gives the "second level" Sixte is asking for. There's nothing stopping a consumer from importing the private modules, but I feel that if your module makes it clear that the public module has the stable API, then that might be good enough.
Example:
# private.nim
const
a* = 5
b* = 7
# public.nim
import private
export private.a
# consumer.nim
import public
echo a # => 5
# echo b # does not compile
".privateimport." is long, but ".all." is too short. It would be a difficult thing to search. If I'm new to nim and see {.all.}, I might not know where to learn what's going on. It almost looks like a typo. "Did they mean 'call'?" It's so short that it's line-noise.
I'm not convinced that "private" would confuse anyone. In C++, anything that has access to "private" has access to the rest also. Nobody thinks it should be "private_plus_protected_and_also_public". I guess someone who doesn't understand "export" could be confused about whether it refers to un-exported symbols.
How about
import foo {.everything.}
That seems clear and human-readable.
I most like import[all]. It is true, as @timotheecour points out in the GH thread, that a new keyword like importAll is less extensible, but I'm not sure how important that property is.
Another undiscussed question is what happens if you do:
importAll foo
export foo
I.e., does this exportAll or just export as a regular export would work now?I can of get what you're suggesting, and I do indeed find Nim public/private limiting and do want a public/package-internal/module-private distinction.
I strongly suggest you to add new lines to your text though.