Electric Froth

______ _ ______ ( / // _/_ o ( / _/_ / /-- // _ _, / _ , _, -/--_ __ / /_ (/____/(/_(/_(__(__/ (_(_(__ _/ / (_(_)(__/ /_

up

Nim! pt6 - I learned a bit about modules

by Joel Kleier on 2014-11-09


In my last post on Nim, I was learning a lot about the SDL2 wrapper. In my post Nim! pt3 I had expressed that I still didn’t quite understand how TFPSmanager was able to get imported into the example’s scope with just the statement import sdl2/gfx. I’ve figured that bit out (because, you know, I read a little more…​) and I’d like to talk about Nim’s modules briefly.

Modules in Nim are defined much like modules in Python (at least on the surface) — the folder and filename provide the module segments used with the import statement. That’s pretty much where the comparison to Python ends.

The import statement itself can use what I refer to as a dot-notation (import path.to.module), or a slash-notation (import path/to/module). The path/to/module part is the file path, including the filename, of a`.nim` file (without the .nim portion). What is very different to Python is that, in the statement import path/to/module, path/to/ is not part of the namespace! The "namespace" is still just module. Therefore, as far as I can tell, the only way to resolve conflicts between module names is to use an alias.

For example:

import lib.ent.entity_manager
import lib.flush.entity_manager
entity_manager.init

Would be in conflict, but:

import lib.ent.entity_manager
import lib.flush.entity_manager as flush_emgr
entity_manager.init
flush_emgr.init

Would disambiguate the module names and resolve any conflicts.

Which leads me to my unanswered question in Nim! pt3! Nim’s modules, by default, sort of import everything from a module specified in an import statement. Only when there is ambiguity does a module prefix need to be specified for a call to a member of the module.

If two or more modules with different names import the same member, then you can resolve the situation in a couple different ways. First, you can indeed prefix the module name onto the member call, and the other way would be to alias the member in a from import statement (IE from lib.ent.entity_manager import init as emgr_init).

There are a couple of other neat things that Nim does with it’s module system:

  1. There is an export statement to do "symbol forwarding" so clients of a particular module don’t have to include that modules dependancies. IE if entity_manager requires entity, and a client of the entity_manager module would need to make use of definitions in entity in order to use members of entity_manager, the entity_manager module could have a statement like export entity.TEntity to let any client that imports entity_manager have access to TEntity from it’s own namespace (IE entity_manager.TEntity)

  2. import statements can be followed by an except statement, which lets clients do the inverse of what the from x import y syntax let’s you do!

  3. In order to be used outside a module, a member must be defined as being exported

Haven’t really written much useful code besides some tests for this, but I think next time I talk about Nim, I might start an actual project that I can discuss. I feel like I have a pretty good (very) basic understanding of the syntax, and I need to have some sort of project to movtivate further learning of Nim and it’s capabilities and usefulness to me.

Until next time!