Last update January 17, 2007

Import Conflict Resolution



Import conflict resolution

ToDo:This page probably needs to be completely reworked (if not deleted). Much of this discussion (especially the syntax alternatives) is pointless now that DMD 0.163 includes "static import", importing as an alias, and even selective importing ( NG:digitalmars.D.announce/4289). See DigitalMars:d/module.html for syntax details. -- JustinCalvarese

Prologue


Assumptions

Imports are private by default (and they are in DMD 0.163).


Terminology

FQN
Fully Qualified Name.
visible
The compiler acknowledges the existance of the member.
accessible
The compiler allows references to the member by name.
multi-import
A syntax/functionality which makes multiple names available in the current scope. This is what the current import does.

Problems/Issues

A: Importing 2 modules with the same symbol causes an immediate collision eg.

import std.string;
import std.regexp;
...
find(..); //error std.string.find or std.regexp.find

B: Changes to a module at a later date may cause a collision at a later date.

import a;
import b;
...
foo(..); //calling a.foo.

At later date symbol 'foo' is added to b and now the collision occurs.

Current behaviour

How imports work is that first a name is searched for in the current namespace. If it is not found, then it is looked for in the import list. If it is found uniquely among the imports, then that is used. If it is in more than one import, an error occurs
 - Walter

Import does not import names into the current namespace. It imports them into a secondary namespace, that is looked in *only* if the name isn't found in the current namespace. Alias can then cherry-pick specific symbols out of that secondary namespace and put them in the current namespace, possibly renaming them along the way.
 - Walter

Current solutions

1:

import std.string;
import std.regexp;
alias std.string.find find;
...
find(..); //no error std.string.find is called

2:

import std.string;
import std.regexp;
...
std.string.find(..); //no error FQN is used

Opinions/pros/cons on the current solutions

1:

  • PRO
    • Solves the import conflict for the intended symbol.
  • CON
    • Does NOT solve future symbol conflicts.
    • The alias is 'physically' seperate from the import.
2:
  • PRO
    • Solves the import conflict for the intended symbol.
  • CON
    • Does NOT solve future symbol conflicts.
    • Causes more verbose code.
Neither of these current solutions solves B.

HelmutLeitner: Proposed addition to 2/CON:

    • Changing library file structure breaks application code

Proposed solutions

3: FQN Import

Don't do the "multi-import" (the import of the module members), only allow FQN access. (AKA "static import")

static import std.string; //exact syntax may vary
static import std.regexp; //exact syntax may vary
...
find(..); //error
std.string.find(..); //ok
std.regexp.find(..); //ok

All 'static import' does is eliminate the "if the name is not found in the current module, look in the imports" step. This has the effect of requiring the use of FQN's when referencing imports.
 - Walter

4: Aliasing Import

Import into a custom namespace, eg.

import std.string str; //exact syntax may vary
import std.regexp;
...
str.find(..); //calls std.string.find
find(..); //calls std.regexp.find

This method should also prevent import into the "secondary namespace".

This method may also force names to be fully qualified with the custom namespace id. See Solution Details below for voting on this aspect.

  std.string.find(..); // Disallowed as 'std.string' is now known as 'str'.
To force the current module name to be used a FQN then use ...
import std.string std.string;

5: Selective Import

Allow selective import of the exact symbol which is required.

import std.string.find; //exact syntax may vary
...
find(..); //calls std.string.find

No other symbols would be imported or become accessible.

5U: Universal Selective Import

Same as above, but allow ANY symbol to be selectively imported. In other words:

Imports a specified symbol/entity by its base name, making it accessible by its base name in the current namespace (and only so).

//exact syntax may vary, obviously
SELECTIVEIMPORT std.string; // "string" becomes available in the current namespace
...
string.find(..); //calls std.string.find

In the case of importing modules, formally equivalent to the following aliasing import:

IMPORTALIAS std.string AS string;

Opinions/pros/cons on the various solutions

3: FQN Import

  • PRO
    • Solves the import conflict for the intended symbol.
    • Solves future symbol conflicts in the same module(s).
  • CON
    • Causes more verbose code, using FQN all the time. (could be solved by having a "using" statement along with import")
4: Aliasing Import
  • PRO
    • Solves the import conflict for the intended symbol.
    • Solves future symbol conflicts in the same module(s).
    • Solves the ability to force FQN usage.
5: Selective Import
  • PRO
    • Solves the import conflict for the intended symbol.
  • CON
    • It is very verbose when one wants to import many symbols from the same module.
5U: Universal Selective Import
  • PRO
    • Solves the import conflict for the intended symbol.
    • (vs 5) No verbosity problems (just selectively import a module).
    • (vs 4) Shorter syntax than the equivalent aliasing import.
  • CON
    • (vs 4) Does not allow renaming of the imported base name. (can be viewed as PRO :p )

Voting for Solutions

1:

2:

3: FQN Import

  • AndKhropov?
  • RioshinAnHarthen?
4: Aliasing Import 5: Selective Import
  • RioshinAnHarthen?

Voting on Preferred syntax for Proposed Solutions

 (provide example)
3: FQN import

static import std.stdio;
using std.stdio;
  • AndKhropov?
fqnimport std.stdio;
4: Aliasing Import

import stdio = std.stdio, string = std.string, std.date;
  • Dave
  • RémyJAMouëza?
import std.stdio as io;
import std.stdio : io;
import std.stdio io;
import std.stdio = io;
import std.stdio => io;
  • JariMattiMäkelä?
import alias std.stdio io;
import io = std.stdio;
import std.stdio alias io;
alias io import std.stdio; // maybe adapt syntax, maybe "namespace" instead of "alias"?

alias io { // multiple imports, e. g. a collision free library
  import std.stdio; 
  import ...; 
}

alias { // the same but unnamed
  import std.stdio; 
  import ...; 
}
  • HelmutLeitner (please correct me on nonesense, I was not following the ng discussions and I'm not up-to-date with D development or syntax, but frustration with collisions and the need for the creation of clean namespaces without referencing modules is genuine)
5: Selective Import

Voting on Solution Details

Aliased import : #4

  • Use of FQN mandatory. AKA: no multi-import. (Only the aliased module name is imported, the module members are not)
import module.name alias mn;

foo(); // illegal, no qualifier used.
mn.foo(); // Mandatory use of 'mn' qualifier
import module.name alias mn;

mn.foo(); // legal
module.name.foo(); // illegal
import module.name alias mn;

mn.foo(); // legal
module.name.foo(); // legal

FrontPage | News | TestPage | MessageBoard | Search | Contributors | Folders | Index | Help | Preferences | Edit

Edit text of this page (date of last change: January 17, 2007 22:38 (diff))