From 0c81b94df7014a742ea31ee8cdd0acb5a8a89488 Mon Sep 17 00:00:00 2001 From: Andrei Alexandrescu Date: Sat, 4 Feb 2017 08:10:17 -0500 Subject: [PATCH 1/4] Add 'from' for inline imports --- src/object.d | 72 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/object.d b/src/object.d index 2023c443d4..02ebba868c 100644 --- a/src/object.d +++ b/src/object.d @@ -4738,3 +4738,75 @@ template _arrayOp(Args...) } public import core.builtins : __ctfeWrite; + +/** + +Provides an "inline import", i.e. an `import` that is only available for a +limited lookup. For example: + +--- +void fun(from!"std.stdio".File input) +{ + ... use File from std.stdio normally ... +} +--- + +There is no need to import `std.stdio` at top level, so `fun` carries its own +dependencies. The same approach can be used for template constraints: + +--- +void fun(T)(from!"std.stdio".File input, T value) +if (from!"std.traits".isIntegral!T) +{ + ... +} +--- + +An inline import may be used in conjunction with the `with` statement as well. +Inside the scope controlled by `with`, all symbols in the imported module are +made available: + +--- +void fun() +{ + with (from!"std.datetime") + with (from!"std.stdio") + { + Clock.currTime.writeln; + } +} +--- + +The advantages of inline imports over top-level uses of the `import` declaration +are the following: + +$(UL +$(LI The `from` template specifies dependencies at declaration level, not at +module level. This allows reasoning about the dependency cost of declarations in +separation instead of aggregated at module level.) +$(LI Declarations using `from` are easier to move around because they don't +require top-level context, making for simpler and quicker refactorings.) +$(LI Declarations using `from` scale better with templates. This is because +templates that are not instantiated do not have their parameters and constraints +instantiated, so additional modules are not imported without necessity. This +makes the cost of unused templates negligible. Dependencies are pulled on a need +basis depending on the declarations used by client code.) +) + +The use of `from` also has drawbacks: + +$(UL +$(LI If most declarations in a module need the same imports, then factoring them +at top level, outside the declarations, is simpler than repeating them.) +$(LI Traditional dependency-tracking tools such as make and other build systems +assume file-level dependencies and need special tooling (such as rdmd) in order +to work efficiently.) +$(LI Dependencies at the top of a module are easier to inspect quickly than +dependencies spread throughout the module.) +) + +*/ +template from(string moduleName) +{ + mixin("import from = " ~ moduleName ~ ";"); +} From b9c070c969051f7e947505cf4cc234c3bcbe39c6 Mon Sep 17 00:00:00 2001 From: Andrei Alexandrescu Date: Sat, 4 Feb 2017 08:29:09 -0500 Subject: [PATCH 2/4] Add credits --- src/object.d | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/object.d b/src/object.d index 02ebba868c..e7c4929dc6 100644 --- a/src/object.d +++ b/src/object.d @@ -4745,7 +4745,7 @@ Provides an "inline import", i.e. an `import` that is only available for a limited lookup. For example: --- -void fun(from!"std.stdio".File input) +void fun(_import!"std.stdio".File input) { ... use File from std.stdio normally ... } @@ -4755,8 +4755,8 @@ There is no need to import `std.stdio` at top level, so `fun` carries its own dependencies. The same approach can be used for template constraints: --- -void fun(T)(from!"std.stdio".File input, T value) -if (from!"std.traits".isIntegral!T) +void fun(T)(_import!"std.stdio".File input, T value) +if (_import!"std.traits".isIntegral!T) { ... } @@ -4769,8 +4769,8 @@ made available: --- void fun() { - with (from!"std.datetime") - with (from!"std.stdio") + with (_import!"std.datetime") + with (_import!"std.stdio") { Clock.currTime.writeln; } @@ -4781,19 +4781,19 @@ The advantages of inline imports over top-level uses of the `import` declaration are the following: $(UL -$(LI The `from` template specifies dependencies at declaration level, not at +$(LI The `_import` template specifies dependencies at declaration level, not at module level. This allows reasoning about the dependency cost of declarations in separation instead of aggregated at module level.) -$(LI Declarations using `from` are easier to move around because they don't +$(LI Declarations using `_import` are easier to move around because they don't require top-level context, making for simpler and quicker refactorings.) -$(LI Declarations using `from` scale better with templates. This is because +$(LI Declarations using `_import` scale better with templates. This is because templates that are not instantiated do not have their parameters and constraints instantiated, so additional modules are not imported without necessity. This makes the cost of unused templates negligible. Dependencies are pulled on a need basis depending on the declarations used by client code.) ) -The use of `from` also has drawbacks: +The use of `_import` also has drawbacks: $(UL $(LI If most declarations in a module need the same imports, then factoring them @@ -4805,8 +4805,12 @@ $(LI Dependencies at the top of a module are easier to inspect quickly than dependencies spread throughout the module.) ) +See_Also: The $(HTTP forum.dlang.org/post/tzqzmqhankrkbrfsrmbo@forum.dlang.org, +forum discussion) that led to the creation of the `_import` facility. Credit is +due to Daniel Nielsen and Dominikus Dittes Scherkl. + */ -template from(string moduleName) +template _import(string moduleName) { - mixin("import from = " ~ moduleName ~ ";"); + mixin("import _import = " ~ moduleName ~ ";"); } From 06c8ad5d6e27dd5b4cd173e590365a641380c1d6 Mon Sep 17 00:00:00 2001 From: Andrei Alexandrescu Date: Sat, 24 Jul 2021 13:56:56 -0400 Subject: [PATCH 3/4] Rename _import to import_ --- src/object.d | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/object.d b/src/object.d index e7c4929dc6..8d30198170 100644 --- a/src/object.d +++ b/src/object.d @@ -4745,7 +4745,7 @@ Provides an "inline import", i.e. an `import` that is only available for a limited lookup. For example: --- -void fun(_import!"std.stdio".File input) +void fun(import_!"std.stdio".File input) { ... use File from std.stdio normally ... } @@ -4755,8 +4755,8 @@ There is no need to import `std.stdio` at top level, so `fun` carries its own dependencies. The same approach can be used for template constraints: --- -void fun(T)(_import!"std.stdio".File input, T value) -if (_import!"std.traits".isIntegral!T) +void fun(T)(import_!"std.stdio".File input, T value) +if (import_!"std.traits".isIntegral!T) { ... } @@ -4769,8 +4769,8 @@ made available: --- void fun() { - with (_import!"std.datetime") - with (_import!"std.stdio") + with (import_!"std.datetime") + with (import_!"std.stdio") { Clock.currTime.writeln; } @@ -4781,19 +4781,19 @@ The advantages of inline imports over top-level uses of the `import` declaration are the following: $(UL -$(LI The `_import` template specifies dependencies at declaration level, not at +$(LI The `import_` template specifies dependencies at declaration level, not at module level. This allows reasoning about the dependency cost of declarations in separation instead of aggregated at module level.) -$(LI Declarations using `_import` are easier to move around because they don't +$(LI Declarations using `import_` are easier to move around because they don't require top-level context, making for simpler and quicker refactorings.) -$(LI Declarations using `_import` scale better with templates. This is because +$(LI Declarations using `import_` scale better with templates. This is because templates that are not instantiated do not have their parameters and constraints instantiated, so additional modules are not imported without necessity. This makes the cost of unused templates negligible. Dependencies are pulled on a need basis depending on the declarations used by client code.) ) -The use of `_import` also has drawbacks: +The use of `import_` also has drawbacks: $(UL $(LI If most declarations in a module need the same imports, then factoring them @@ -4806,11 +4806,11 @@ dependencies spread throughout the module.) ) See_Also: The $(HTTP forum.dlang.org/post/tzqzmqhankrkbrfsrmbo@forum.dlang.org, -forum discussion) that led to the creation of the `_import` facility. Credit is +forum discussion) that led to the creation of the `import_` facility. Credit is due to Daniel Nielsen and Dominikus Dittes Scherkl. */ -template _import(string moduleName) +template import_(string moduleName) { - mixin("import _import = " ~ moduleName ~ ";"); + mixin("import import_ = " ~ moduleName ~ ";"); } From 65450814e366a1bf02d11d44c2c79a76014aa20a Mon Sep 17 00:00:00 2001 From: Andrei Alexandrescu Date: Fri, 27 Aug 2021 10:23:55 -0400 Subject: [PATCH 4/4] Change `import_` to `imported` --- src/object.d | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/object.d b/src/object.d index 8d30198170..a69787b1b9 100644 --- a/src/object.d +++ b/src/object.d @@ -4745,7 +4745,7 @@ Provides an "inline import", i.e. an `import` that is only available for a limited lookup. For example: --- -void fun(import_!"std.stdio".File input) +void fun(imported!"std.stdio".File input) { ... use File from std.stdio normally ... } @@ -4755,8 +4755,8 @@ There is no need to import `std.stdio` at top level, so `fun` carries its own dependencies. The same approach can be used for template constraints: --- -void fun(T)(import_!"std.stdio".File input, T value) -if (import_!"std.traits".isIntegral!T) +void fun(T)(imported!"std.stdio".File input, T value) +if (imported!"std.traits".isIntegral!T) { ... } @@ -4769,8 +4769,8 @@ made available: --- void fun() { - with (import_!"std.datetime") - with (import_!"std.stdio") + with (imported!"std.datetime") + with (imported!"std.stdio") { Clock.currTime.writeln; } @@ -4781,19 +4781,19 @@ The advantages of inline imports over top-level uses of the `import` declaration are the following: $(UL -$(LI The `import_` template specifies dependencies at declaration level, not at +$(LI The `imported` template specifies dependencies at declaration level, not at module level. This allows reasoning about the dependency cost of declarations in separation instead of aggregated at module level.) -$(LI Declarations using `import_` are easier to move around because they don't +$(LI Declarations using `imported` are easier to move around because they don't require top-level context, making for simpler and quicker refactorings.) -$(LI Declarations using `import_` scale better with templates. This is because +$(LI Declarations using `imported` scale better with templates. This is because templates that are not instantiated do not have their parameters and constraints instantiated, so additional modules are not imported without necessity. This makes the cost of unused templates negligible. Dependencies are pulled on a need basis depending on the declarations used by client code.) ) -The use of `import_` also has drawbacks: +The use of `imported` also has drawbacks: $(UL $(LI If most declarations in a module need the same imports, then factoring them @@ -4806,11 +4806,11 @@ dependencies spread throughout the module.) ) See_Also: The $(HTTP forum.dlang.org/post/tzqzmqhankrkbrfsrmbo@forum.dlang.org, -forum discussion) that led to the creation of the `import_` facility. Credit is +forum discussion) that led to the creation of the `imported` facility. Credit is due to Daniel Nielsen and Dominikus Dittes Scherkl. */ -template import_(string moduleName) +template imported(string moduleName) { - mixin("import import_ = " ~ moduleName ~ ";"); + mixin("import imported = " ~ moduleName ~ ";"); }