DIP10005: Dependency-Carrying Declarations is now available for community feedback

Chris Wright via Digitalmars-d digitalmars-d at puremagic.com
Sat Dec 24 09:52:04 PST 2016


On Sat, 24 Dec 2016 04:34:03 -0500, Andrei Alexandrescu wrote:
> Upon more investigation, I see a large discrepancy between the findings
> of DIP1005 and yours.

There's no discrepancy.

In part, you are misinterpreting most of what I said.

In part, you are assuming that imports on non-template declarations will 
be handled lazily, even though that is not part of this DIP, even though 
that is likewise possible with static and selective imports.

In part, you are using lines of code as a proxy for compile time.

In part, you dispute that this only affects template constraints, but:
* An import used only in the body of a template can be made a local 
import today.
* An import used in the declaration of a templated type or function can 
be addressed by using explicit template syntax, offering a place to 
insert your imports.
* An import used anywhere else must still be processed, even assuming 
this DIP is implemented.
* If, in a future DIP, we make it so that `with(import)` is handled 
lazily, we can also make it so that static and selective imports are 
handled lazily.

> The findings of DIP1005 are the following:
> 
> * Importing a single std module also imports on average 10.5 other
> modules.

Seems reasonable. Between 2 and 3.5 direct dependencies, by my count, and 
you're counting transitive dependencies.

We're concerned with the effects of DIP1005, though, which only affects 
template constraints.

> * Importing a single std module costs on average 64.6 ms.

55-ish for your hardware, you reported elsewhere. 47-ish for mine.

> * (Not stated in the DIP) A majority of std templates would acquire
> inline imports.

Again, that wouldn't impact compile times because these aren't template 
constraints.

You can make a separate DIP to make imports lazy. That can impact static, 
selective, and `with` imports equally well. But it's not part of what 
we're discussing today.

> According to the DIP, one may estimate that the proposed feature would
> reduce additional imports to 0 and the average time to import a single
> module by a factor of 10 to under 10 ms.

"The proposed feature" must be lazy semantic analysis, especially of 
imports. That isn't part of DIP1005.

You won't get to zero additional imports. You might get to zero 
*extraneous* imports -- that is, only the set of imports required to 
create a custom *.di file containing only the parts of the module that 
your application uses.

> By your estimates:
> 
> * 26 templates in std need inline imports.

I said that 26 templates *could possibly benefit from* your new style of 
imports. There's a difference between possibly benefitting from a change 
and needing that change.

> * Importing a single std module today would only imports 1-3 other
> modules most of the time (one or more of std.traits, std.meta, and
> std.range.primitives).

No, that's not what I said at all. I said that the only modules you would 
sometimes *stop* processing because of DIP1005 are std.traits, std.meta, 
and std.range.primitives. That's because those modules contain templates 
used in other modules as template constraints.

In order to get any additional improvements, you need lazy imports, which 
can also apply to static or selective imports without any syntax changes.

> * These additional imports cost in aggregate under 10ms, bringing the
> average cost of importing a module itself to 54.6 ms.

~10ms is the upper bound of the added cost if you import just one module 
in std that has a template constraint you don't use.

The way you state it implies that every module brings in std.traits, 
std.meta, and std.range.primitives unnecessarily, instead of 26 templates 
across at most 26 modules importing them for a reason.

> * It follows that the average module takes 5.46 more times to import
> alone than the sum of std.traits, std.meta, and std.range.primitives
> (which have a total of 11263 lines, 5x more than the average Phobos
> module).

More like 4.7 on my hardware, but yeah. 11k lines that have to be parsed 
and 0 lines that require semantic analysis. Not terribly surprising.

> I don't see how your claims can be simultaneously true with the findings
> of DIP1005.

You found that the average cost of importing a std module is 54ms or 
thereabouts. std.traits, std.meta, and std.range.primitives are well 
below average. No conflict there. They aren't even the cheapest modules 
in the standard library.

The modules in question are mostly unittests. The compiler doesn't run 
semantic on unittests in a module that wasn't included in the command 
line. (Even if you pass -unittest. Try it out -- you can even have a 
unittest that says `static assert(false);` and it does nothing.)

The parts of the modules that are not unittests are templates. The 
compiler doesn't run semantic analysis on templates until you use them.

So it should be pretty obvious why these modules are so cheap to import 
and not use.

> The scripts that compute those numbers are available with
> the DIP. Were you able to reproduce them?

The times it reported on my hardware:

Min: 5ms
Max: 300ms
Median: 21ms
Average: 47ms

The minimum isn't terribly useful because it gets to the point of testing 
the process scheduler and IO more than the compiler. If we want numbers 
that we can trust on the low end, we'll need to put timing information 
into the compiler, maybe control for IO by using a ramfs, that sort of 
thing.

You also reproduced my test, so this isn't a quirk of my installation.


More information about the Digitalmars-d mailing list