Ion: Transitive imports of symbols

Hi,

After having written some more ion code, I encountered yesterday my first name collision.

The main cost of the having all symbols contributed to a global namespace is that it creates collisions that can sometimes only be corrected by touching an intermediate module (rather than the module you're actively working on right now)

Imagine you have a main program residing in module: Program, using modules ModuleHello, ModuleWorld.

If ModuleHello imports ModuleBits unqualified:

1
import modulebits {...} 


Then any symbol from modulebits can collide with symbols of Program. The person having added the colliding symbol in Program might now has to chase all imports of modulebits and correct the importing module to import names with local qualified names.

Workarounds are:
1. to create generally unique names in modules (it's probably a good practice anyway, as it improves searchability) ; it's inevitable however that they will happen. Whether it indicates lack of reuse or bad naming, I don't know
2. always import qualified, explicitely:
import modulebits { modulebits_fn = fn } (although this still delays the inevitable collision when someone attempts to also import the same module

Those workaround require discipline, which is always in short-supply ;)

Oberon07 does not have this issue because:
- symbols have to be explicitly exported from a module.
- symbols imported via IMPORT are not themselves exported


Edited by Nicolas Léveillé on Reason: Initial post
Right now transitively imported symbols shouldn't be imported when you import via {...}. The current logic for that is not final, but import_all_package_symbols currently only imports symbols that are located in their home package. So if Program does import ModuleHello {...} and ModuleHello does import ModuleBits {...}, Program will only see symbols that are natively defined in ModuleHello. If that doesn't work currently, it's a bug--it is intended to work and it used to work. That kind of thing is essential to making bulk imports usable in the real world. Whether or not a package's implementation uses one style of imports or another shouldn't leak into its interface. The downside is that with the current non-final logic there's no way to explicitly re-export a non-home symbol, but that will be supported.

Aside from that, it's been on my TODO list for a while to support a more traditional package name prefixed approach to avoid doing either bulk imports or explicitly listed imports. I'll try to do that today.

Once I develop more tooling around the core compiler, one of the planned refactoring operations is to replace unqualified imported symbol references with fully qualified symbol references, so you can, for example, start with a low-friction, bulk import workflow and seamlessly move to something more robust if/when it becomes necessary. That would also make it easy to refactor code from one package into multiple packages. E.g. you start with everything in package A and now want to move some code into a subpackage B. You can just copy and paste the code into the B directory and add import B {...} to a file in package A and everything will keep working as long as none of the symbols now defined in B were externally bulk imported. And if necessary you can then at that point or later run the refactoring tool to make the B symbol references fully qualified and remove the {...} import.

Edited by Per Vognsen on
I rechecked and indeed could not reproduce the case I thought I had encountered! So all is well.

Having a tool to ease the transition from frictionless import {...} to a more precise one sounds really convenient.