On Thursday, 13 September 2018 at 11:58:40 UTC, rikki cattermole wrote:
On 13/09/2018 11:54 PM, Jonathan Marler wrote:
"Selective imports" limit the symbols imported from a module by providing a list of all the symbols to include:

import std.stdio : writeln, writefln;

The complement of this would be a "Filtered import", meaning, import all the symbols except the ones in the provided list. I imagine the syntax would look something like:

import std.stdio ~ writeln, writefln;


To provide a use case for this, say you have a module that uses a fair amount of symbols from `std.file` but you want to make sure that all calls to `chdir` are logged.  Using a filtered import would allow you to exclude `chdir` from being available globally so you could create a wrapper that all code is forced to go through.

import std.stdio;
import std.file ~ chdir;

void chdir(R)(R path)
{
     writefln("chdir '%s'", path);
     from!"std.file".chdir(path);
}

It's an interesting variation on D's current repertoire of import semantics. Possibly worth consideration as an addition to the language.

Grammar Changes:
-----------------------------------------------------
ImportBindings:                    (existing rule)
     Import : ImportBindList        (existing rule)
     Import ~ ImportExcludeList     (new rule)

ImportExcludeList:                 (new rule)
     Identifier, ImportExcludeList  (new rule)
-----------------------------------------------------

import std.stdio;
import std.file;

void chdir(R)(R path) {
        writeln("changing dir to ", path);
    std.file.chdir(path);
}


void main()
{
    chdir("/tmp");
}

Ah, I see. Poor example on my part. I didn't realize that local symbols ALWAYS take precedence over imported ones. I thought that the compiler would "fall back" to an imported symbol if the local one didn't work, but it appears that's not the case.

Some more thoughts. Selective imports and filtered imports are complements to each other, you can still have all the functionality you want with just one of them, but one will usually fit better in each case. Namely, if you want a small number of symbols from a module, selective imports are the way to go, but if you want to include all except a small number of symbols from a module, then filtered imports would be nice.

So a use case would only work better with filtered imports if it was a scenario where we want to include all except a few symbols from an imported module. Given that, the next question is, in what cases do we want to prevent symbols from being imported from a module? The immediate example is to resolve symbol conflicts.

// assume both modules provide the symbol baz
import foo;
import bar;

baz(); // symbol conflict

// change `import foo;` to `import foo ~ baz;`

And to reiterate, we could also resolve this conflict with selective imports (or even static or named imports in this case) so you would only consider this useful in cases where we are using a good amount of symbols from foo as to make it cumbersome to have to selectively import all the symbols or qualify them all in source, i.e.

import foo : a, b, c, d, e, f, g, h, i, j, k, ...;
// vs
import foo ~ baz;

Anyway, those are my thoughts on it. Again I think it's something to consider. I'm not sure if it has enough uses to justify an addition to the language (that bar is pretty high now-a-days). So it's up to us D programmers to think about whether these semantics would work well in our own projects.

Reply via email to