The linters I've used discourage the first option because it's then difficult to know where thing1 and thing2 come from. So I'm in the habit of using the latter 2 options.
But in Nim, it seems like the preference is the "import everything" method (e.g. import osproc). It's less typing, for sure, but it makes it harder to read a file and know where things are coming from. For instance, I'm trying to figure out how osproc.suspend works and it uses suspendThread underneath (see https://github.com/nim-lang/Nim/blob/master/lib/pure/osproc.nim#L597). But it's not obvious which of the imported modules defines suspendThread.
I understand that, different from Python, Nim supports overloading, and so variants of suspendThread could actually be defined in several of the modules. How, then do you track down where a proc is coming from? I suppose I can grep a lot, but is there a better way?
Firstly, that you "know" where stuff comes from in dynamically typed Python is a pure myth. In obj.methodCall you don't know obj's type, so you don't "know" where methodCall comes from at all. It's far worse than in Nim.
Secondly, you can and should ask nimsuggest to see where stuff comes from.
If you wish to get into the habit of it, you can also:
from x import nil
Then, in your code, reference x.thing1 and x.thing2.
Or, if the module name is really long or involves directory separation:
from reallylongname/subdir/awesomelib as x import nil
To make such behavior even more possible, I'm thinking of writing a PR to support Nim importing associated methods when an object is explicitly pulled. That would allow:
from x import ThingObject
to import not just ThingObject but also any methods/procs that have ThingObject as the first parameter.
But, I'm still learning Nim and I'll definitely wait until 1.0 is out before making such a PR. I have the impression they have enough stuff on the plate right now.
I'm a big fan of explicitness. (And, I like old-school paper printouts to do debugging and study.)
Firstly, that you "know" where stuff comes from in dynamically typed Python is a pure myth. In obj.methodCall you don't know obj's type, so you don't "know" where methodCall comes from at all. It's far worse than in Nim.
True, but t's about transparency, not language guarantees. I'm interested in helping non-experts to read my source-code on the web, as Nim is not a well-known language. I agree with @JohnAD, and I think his method-import idea would help.
I recognize a trade-off in programmer productivity; explicitness can be painful for coders while helpful to readers. That's a better argument.
As for the lack of language guarantees, Ruby encourages metaprogramming, while Python merely allows it. I don't find many Python repos that are so tricky.
Wildcard imports (from <module> import *) should be avoided, as they make it unclear which names are present in the namespace, confusing both readers and many automated tools. There is one defensible use case for a wildcard import, which is to republish an internal interface as part of a public API (for example, overwriting a pure Python implementation of an interface with the definitions from an optional accelerator module and exactly which definitions will be overwritten isn't known in advance).
Thanks, Guido.
Somewhat related to this, and perhaps I'm only thinking about it because I haven't yet used an editor with good integration (I'm on Sublime and it didn't work out of the box), perhaps it would be useful in the HTML documentation to list all the procs that apply to a type. For instance, if I have this code:
import strutils
type
Person* = tuple[name: string, age: int]
Food* = tuple[name: string]
proc greet*(person: Person) =
## Print a greeting for a person
echo "Hello to ", person.name
proc snub*(person: Person) =
## Snub a person. Do nothing.
echo ""
proc rename*(person: Person, new_name: string): Person =
## Return a new Person with a different
## name.
return (name: new_name, age: person.age)
proc eat*(food: Food) =
## Consume some food
echo "That was yummy ", food.name
proc lookAt*[Thing](thing: Thing) =
## Look at something
echo "You look at ", thing.name
Then the HTML documentation for that would look something like (where clicking the proc would take you to the full definition):
Types
-----------------
Person = tuple[name: string, age: int]
- proc greet(person: Person)
- proc snub(person: Person)
- proc rename(person: Person; new_name: string): Person
- proc lookAt[Thing](thing: Thing)
Food = tuple[name: string]
- proc eat(food: Food)
- proc lookAt[Thing](thing: Thing)
Procs
-----------------
...
Mockup: https://gist.github.com/iffy/f45d78e8aaee68d9540c5861a833ecd8#file-option1-png
Or perhaps format it UCFS-style and include the first line of the documentation comment, like this:
Types
-----------------
Person = tuple[name: string, age: int]
- .greet() - Print a greeting for a person
- .snub() - Snub a person. Do nothing.
- .rename(new_name: string): Person - Return a new Person with a different name.
- .lookAt() - Look at something
Food = tuple[name: string]
- .eat() - Consume some food
- .lookAt() - Look at something
Procs
-----------------
...
Mockup: https://gist.github.com/iffy/f45d78e8aaee68d9540c5861a833ecd8#file-option2-png
This would let me easily discover all the things I can do to a Person or Food. Even better if it could list all applicable procs from other modules, too (fully qualified).
Just ideas from a newb trying to figure things out.