digitalmars.D - Inline imports redivivus
- Per =?UTF-8?B?Tm9yZGzDtnc=?= (4/8) Mar 07 2022 https://forum.dlang.org/post/sdehom$10fi$1@digitalmars.com
- =?UTF-8?Q?Ali_=c3=87ehreli?= (27/33) Mar 07 2022 This seems to be yet another example of the need for template string
- Paul Backus (4/10) Mar 08 2022 There's always strings:
- =?UTF-8?Q?Ali_=c3=87ehreli?= (22/25) Mar 08 2022 But you give me the idea that if we allow "this template parameter is a
- H. S. Teoh (12/26) Mar 08 2022 [...]
- =?UTF-8?Q?Ali_=c3=87ehreli?= (8/9) Mar 08 2022 I know but they are still strings.
- Zach Tollen (47/55) Mar 10 2022 The reason I wanted to revive this redivivus — so to say — is
- =?UTF-8?Q?Ali_=c3=87ehreli?= (23/26) Mar 11 2022 Perhaps a second meaning for ..? And is : really necessary? So, would
- Zach Tollen (53/80) Mar 11 2022 If you used `..` here you would always have to add whitespace in
- Zach Tollen (25/26) Mar 12 2022 The character `|` might work too. It looks better if we close it
- Daniel N (9/35) Mar 12 2022 Out of your new alternatives, I like this one the best.
- Zach Tollen (78/86) Mar 12 2022 Thanks. Those are good points. I think I even agree with you.
- Dom DiSc (12/13) Mar 13 2022 Locality can be overdone. I think this would suffice:
- Dom DiSc (4/5) Mar 13 2022 And btw. foreach doesn't even introduce a new scope, so you can't
- zjh (5/6) Mar 13 2022 Agree,
- Adam D Ruppe (2/3) Mar 13 2022 Yes it does.
- Tejas (5/10) Mar 13 2022 `foreach` **does** introduce a new scope
- bauss (9/20) Mar 15 2022 Would be nice if we could attribute static foreach like this
- Andrea Fontana (8/14) Mar 15 2022 ```d
- bauss (3/20) Mar 15 2022 The whole point is to avoid the extra brackets and/or the extra
- Zach Tollen (212/223) Mar 15 2022 There are three considerations here:
https://forum.dlang.org/post/sdehom$10fi$1 digitalmars.com On Friday, 23 July 2021 at 13:55:34 UTC, Andrei Alexandrescu wrote:If it works well in practice, a future language proposal could take `_import!"std.datetime".SysTime` to the simpler and better `import(std.datetime).SysTime`.Yes, please!
Mar 07 2022
On 3/7/22 02:27, Per Nordlöw wrote:https://forum.dlang.org/post/sdehom$10fi$1 digitalmars.com On Friday, 23 July 2021 at 13:55:34 UTC, Andrei Alexandrescu wrote:This seems to be yet another example of the need for template string arguments typed as symbols in the source code. - Flag!"foo" could become Flag(foo) (or more consistently Flag!foo). - bitfields could become bitfields!(int, x, 8) instead of bitfields!(int, "x", 8)[*] Andrei mentioned a couple of times that this is what was discussed as "new alias" in the past where the template allows the use of an "unknown" (or "new") symbol at call site. I see a strong similarity here to the existing opDispatch() that makes compile-time strings from "unknown" symbols at call site. Ali [*] I think it would be interesting to come up with a language solution that would e.g. enable combining each three consecutive arguments of bitfields. It is a code smell that everybody knows that the three separate arguments go together but we don't use a language construct for that. We already have the following method in the current language but it is obviously redundant and perhaps that's why the current design of bitfields does not use it: bitfields!(Bit(int, x, 8), // Better but redundant Bit(int, y, 8)); A solution that would allow the following would be interesting: bitfields!(int x : 8, int y : 8); So, we somehow specify at template definition that two (or three?) parameters (e.g. int and x) can be specified without a comma and perhaps anything after ':' are UDAs of that parameter?If it works well in practice, a future language proposal could take `_import!"std.datetime".SysTime` to the simpler and better `import(std.datetime).SysTime`.Yes, please!
Mar 07 2022
On Monday, 7 March 2022 at 18:45:54 UTC, Ali Çehreli wrote:
A solution that would allow the following would be interesting:
bitfields!(int x : 8,
int y : 8);
So, we somehow specify at template definition that two (or
three?) parameters (e.g. int and x) can be specified without a
comma and perhaps anything after ':' are UDAs of that parameter?
There's always strings:
bitfields!("int x : 8",
"int y : 8");
Mar 08 2022
On 3/8/22 14:28, Paul Backus wrote:There's always strings:And they are the eyesore! :)bitfields!("int x : 8", "int y : 8");But you give me the idea that if we allow "this template parameter is a string" and don't require strings at the use site, then it would work for the above case as well. Basically, the string is contains my domain specific language as you show and I can do anything I want with it. Brain storming with a 'new string' syntax: template bitfields(new string args...) { // ... } bitfields!(int x : 8, int y : 8); And the template instance sees two strings: "int x : 8" and "int y : 8" and has fun parsing them at compile time. Again, this feels natural to me because it is related to opDispatch. Of course there are syntax issues: Nothing that takes part in a parameter list can be a part of the string. I think they are just ',' to allow multiple 'new string' parameters and ')' to allow closing the parameter list. When needed, they could be written with backslashes as \, and \). Wow! I've just written a DIP! :P Ali
Mar 08 2022
On Tue, Mar 08, 2022 at 03:25:49PM -0800, Ali Çehreli via Digitalmars-d wrote:On 3/8/22 14:28, Paul Backus wrote:[...] Token strings are your friend: bitfields!q{ int x:8; int y:8; }; Or, if you like struct-like syntax: bitfields!q{ int x:8; int y:8; }; T -- Questions are the beginning of intelligence, but the fear of God is the beginning of wisdom.There's always strings:And they are the eyesore! :)bitfields!("int x : 8", "int y : 8");But you give me the idea that if we allow "this template parameter is a string" and don't require strings at the use site, then it would work for the above case as well. Basically, the string is contains my domain specific language as you show and I can do anything I want with it.
Mar 08 2022
On 3/8/22 17:15, H. S. Teoh wrote:Token strings are your friend:I know but they are still strings. Flag!"foo" a; // Meh Flag!`foo` b; // Meh Flag!q{foo} c; // No comment... D'oh! :) Flag!foo d; // Unavailable This is a minor thing only Ali dislikes... :/ Ali
Mar 08 2022
On Monday, 7 March 2022 at 10:27:08 UTC, Per Nordlöw wrote:https://forum.dlang.org/post/sdehom$10fi$1 digitalmars.com On Friday, 23 July 2021 at 13:55:34 UTC, Andrei Alexandrescu wrote:The reason I wanted to revive this redivivus — so to say — is because I believe the following syntax is near-optimal for the task at hand: `import.std.datetime:SysTime` From my perspective there is no need to rely on advanced template features since inline imports are so basic that they should be adopted as a language feature instead. The above syntax is excellent because: - It is grammatically unambiguous - It requires no parentheses or other enclosing marks - It resembles selective imports That is exactly what it is: a use-once, selective import. You use it as a drop-in replacement for the identifier you want to import. In reviewing the historical proposals even as far back as DIP1005 [1], it seems that the syntax above simply wasn't stumbled upon. Therefore I wanted it to be evaluated. "Destroy!" To give a little more food for thought, in addition to the above syntax, I wanted to introduce a stunning syntax sugar, which uses `$` instead of `import .` as a special token to activate the sequence: `$std.datetime:SysTime` This is the tersest fully qualified inline import possible. I suppose it is strange on the eyes. But don't implement it unless you want people to use it, because people can hardly resist a concise syntax like this! Anyway, those are my proposals. Here are some previous proposals and why I have problems with them: ```d imported!"std.datetime".SysTime // - already implemented in object.d [2] // - best you can do with existing language // - can't use keyword `import` // - requires `""` and `!` import(std.datetime).SysTime // parens unnecessary (import std.datetime).SysTime // ditto std.datetime::SysTime // grammatically ambiguous (module name unclear) ::std.datetime:SysTime // if we put the `::` first it becomes viable // it's a different version of the `$` ``` [1] https://github.com/dlang/DIPs/blob/master/DIPs/other/DIP1005.md#syntactic-alternatives [2] https://github.com/dlang/druntime/pull/1756/filesIf it works well in practice, a future language proposal could take `_import!"std.datetime".SysTime` to the simpler and better `import(std.datetime).SysTime`.Yes, please!
Mar 10 2022
On 3/10/22 22:48, Zach Tollen wrote:
::std.datetime:SysTime // if we put the `::` first it becomes
viable
// it's a different version of the `$`
Perhaps a second meaning for ..? And is : really necessary? So, would
the following work?
..std.datetime.Systime
Now it seems to have a different meaning from "importing" though. In
this case it feels like we are "using" Systime from that module. And the
rationale for .. can be:
- Single dot already means "this module".
- Two dots may mean "outside of this module".
Going off topic and without knowing whether this topic has already been
brought up, should inline imports automatically be made available to the
callers of functions? Arbitrarily using the $ syntax:
module my.module;
void foo($bar:SomeSymbol a) {
}
Since 'foo' is public to the users of my.module, should we expect the
users be able to call 'foo' without importing SomeSymbol separately
themselves? And the next question may be what if SomeSymbol is
accessible to my.module but not to my users (e.g. if it's 'package').
So, if it should automatically be imported for the users, should
SomeSymbol automatically be raised to 'public' status for the users of
'foo'?
Ali
Mar 11 2022
Thanks for your reply! On Friday, 11 March 2022 at 13:01:43 UTC, Ali Çehreli wrote:On 3/10/22 22:48, Zach Tollen wrote:If you used `..` here you would always have to add whitespace in an ordinary call chain, to avoid ambiguous lexing, so it's not good: ```d { x = normal.call.chain; x = dotdot.call. ..modname:chain; // space necessary to avoid lexing as `...` } ``` As far as not wanting to use `:` the issue is also ambiguity. In DIP1005, written a few years ago by Andrei Alexandrescu, this exact question was addressed [1]. Quote: ```d void process(import.std.stdio.File input); struct Buffered(Range) if (import.std.range.isInputRange!Range) { ... } ``` "Such an option has an ambiguity problem shown by Timon Gehr: is import.std.range.isInputRange looking up symbol isInputRange in module/package std.range, or the symbol range.isInputRange (e.g. a struct member) in module/package std?"::std.datetime:SysTime // if we put the `::` firstit becomesviable // it's a different versionof the `$`Perhaps a second meaning for ..? And is : really necessary? So, would the following work? ..std.datetime.Systime- Single dot already means "this module". - Two dots may mean "outside of this module".If we can find a starting token (other than `$`) which allows the construct to seem familiar and which has no other problems, I'm all for it. `::` has been suggested. I believe also `:` would work: ```d auto x = :std.datetime:Systime; ``` Technically, `:` would not cause grammatical ambiguity. But I don't think it's visually distinct enough, and the error messages you get if you don't type it correctly would be confused with the compiler's other error messages for `:` syntaxes. At minimum, `$` as in `$fully.qualified:symbol` announces its presence boldly, as if to challenge the language designer to come up with a better use of the `$` token. :-)Going off topic and without knowing whether this topic has already been brought up, should inline imports automatically be made available to the callers of functions? Arbitrarily using the $ syntax: module my.module; void foo($bar:SomeSymbol a) { } Since 'foo' is public to the users of my.module, should we expect the users be able to call 'foo' without importing SomeSymbol separately themselves?I would say no. As a one-use import, it doesn't spread its import anywhere but to itself. But the caller can just call using `foo($bar:SomeSymbol(value))` if they don't feel like importing the module either.And the next question may be what if SomeSymbol is accessible to my.module but not to my users (e.g. if it's 'package'). So, if it should automatically be imported for the users, should SomeSymbol automatically be raised to 'public' status for the users of 'foo'?Again, no. If a function parameter requires a privately defined structure, then that function is not meant to be called by things which don't have access to that structure. Inline imports are semantically no different from symbols which had their modules imported separately. I'm pretty sure issues of privacy won't be affected by this. - Zach [1] https://github.com/dlang/DIPs/blob/master/DIPs/other/DIP1005.md#syntactic-alternatives
Mar 11 2022
On Friday, 11 March 2022 at 13:01:43 UTC, Ali Çehreli wrote:Perhaps a second meaning for ..? And is : really necessary?The character `|` might work too. It looks better if we close it with the same character. ```d x = |std.datetime|SysTime; ``` I actually like this one a lot. There is some potential lexical ambiguity with `|` and `||` as binary operators. However, those operators are typically separated with whitespace in ordinary code, so I don't think it will ever be a problem. (The second `|` in `|std.datetime|SysTime` can be parsed as a part of `|modname|symbol`, so apart from typos, there's no syntactical problem.) The worst you would suffer would be the visual confusion of something like this: ```d if (|std.something|condition(sdfd) || |some.other.inlinemodule|Test || |othermod.imp|mycondition) { myFlags = |std.something|Flagset | |std.otherthing|Flags; } ``` This would be the extreme case I think. Syntax highlighting could help. I think this is better than `$std.datetime:SysTime`.
Mar 12 2022
On Saturday, 12 March 2022 at 19:13:33 UTC, Zach Tollen wrote:On Friday, 11 March 2022 at 13:01:43 UTC, Ali Çehreli wrote:Out of your new alternatives, I like this one the best. ```d x = :std.datetime:SysTime; ``` 1) It is symmetric same as || 2) : is already used in import x:y 3) : is not used in expressions unlike | which is quite common. 4) We can keep $ for some future codegen features.Perhaps a second meaning for ..? And is : really necessary?The character `|` might work too. It looks better if we close it with the same character. ```d x = |std.datetime|SysTime; ``` I actually like this one a lot. There is some potential lexical ambiguity with `|` and `||` as binary operators. However, those operators are typically separated with whitespace in ordinary code, so I don't think it will ever be a problem. (The second `|` in `|std.datetime|SysTime` can be parsed as a part of `|modname|symbol`, so apart from typos, there's no syntactical problem.) The worst you would suffer would be the visual confusion of something like this: ```d if (|std.something|condition(sdfd) || |some.other.inlinemodule|Test || |othermod.imp|mycondition) { myFlags = |std.something|Flagset | |std.otherthing|Flags; } ``` This would be the extreme case I think. Syntax highlighting could help. I think this is better than `$std.datetime:SysTime`.
Mar 12 2022
On Saturday, 12 March 2022 at 19:33:16 UTC, Daniel N wrote:Out of your new alternatives, I like this one the best. ```d x = :std.datetime:SysTime; ``` 1) It is symmetric same as || 2) : is already used in import x:y 3) : is not used in expressions unlike | which is quite common. 4) We can keep $ for some future codegen features.Thanks. Those are good points. I think I even agree with you. Regarding (3), there is an exception in the case of the conditional operator (`? :`), but I don't think it's a huge problem. The worst visual confusion here might be something like: ```d { auto x = :mymod.question:ask ? :another.modname:asdf ? :moremods:answer1 : :finalmod.three:okay : :mymod.answer:two } ``` To do a general comparison of the versions, let's take this code snippet from [phobos](https://github.com/dlang/phobos/blob/16cb085b584f100fa677e2e64ff6b6dbb4921ad1/std/algorithm/comparison.d#L88): The way it is now: ```d if (Values.length != 0) { foreach (uint i, ref v; values) { import std.functional : binaryFun; if (binaryFun!pred(value, v)) return i + 1; } return 0; } ``` Ugh. Not my favorite. Now let's look at the [pull request](https://github.com/dlang/druntime/pull/1756/files) which was already merged, which allows you to write the following: ```d if (Values.length != 0) { foreach (uint i, ref v; values) { if (imported!"std.functional".binaryFun!pred(value, v)) return i + 1; } return 0; } ``` I'd say this represents 70% of the total aesthetic improvement between the versions. Just being able to inline imports makes most of the difference here — not bad for a technique with no language support! (We're not talking about compilation speed, although direct language support would allow the compiler to bypass the normal lookup process and go straight to module where the import is located, so it would speed up.) Using my language-supported long form `import` syntax, the result is: ```d if (Values.length != 0) { foreach (uint i, ref v; values) { if (import.std.functional:binaryFun!pred(value, v)) return i + 1; } return 0; } ``` I'll give this 5% of the total aesthetic improvement, from the previous version to this. Finally, with `:modname:symbol`: ```d if (Values.length != 0) { foreach (uint i, ref v; values) { if (:std.functional:binaryFun!pred(value, v)) return i + 1; } return 0; } ``` I give this the remaining 25% of the total improvement. I'm curious what other people think.
Mar 12 2022
On Saturday, 12 March 2022 at 23:57:09 UTC, Zach Tollen wrote:I'm curious what other people think.Locality can be overdone. I think this would suffice: ```d if (Values.length != 0) { import std.functional : binaryFun; foreach (uint i, ref v; values) if (binaryFun!pred(value, v)) return i + 1; return 0; } ``` So any new feature is here totally superfluous IMHO.
Mar 13 2022
On Sunday, 13 March 2022 at 08:23:52 UTC, Dom DiSc wrote:So any new feature is here totally superfluous IMHO.And btw. foreach doesn't even introduce a new scope, so you can't get your import more local than in my version, no matter what new syntax you invent.
Mar 13 2022
On Sunday, 13 March 2022 at 08:37:15 UTC, Dom DiSc wrote:Agree, There is no need to be too `local` at all. You only need to put the same `imported file` function into one file.So any new feature is here totally superfluous IMHO.
Mar 13 2022
On Sunday, 13 March 2022 at 08:37:15 UTC, Dom DiSc wrote:And btw. foreach doesn't even introduce a new scopeYes it does.
Mar 13 2022
On Sunday, 13 March 2022 at 08:37:15 UTC, Dom DiSc wrote:On Sunday, 13 March 2022 at 08:23:52 UTC, Dom DiSc wrote:`foreach` **does** introduce a new scope I believe it is `static foreach` that **doesn't** introduce a new scope(hence why you see `static foreach(){{ /*code/* }}` style code sometimesSo any new feature is here totally superfluous IMHO.And btw. foreach doesn't even introduce a new scope, so you can't get your import more local than in my version, no matter what new syntax you invent.
Mar 13 2022
On Sunday, 13 March 2022 at 12:47:05 UTC, Tejas wrote:On Sunday, 13 March 2022 at 08:37:15 UTC, Dom DiSc wrote:Would be nice if we could attribute static foreach like this instead: ```d scope static foreach (...) { ... } or static foreach (...) scope { ... } ``` Would've been much cleaner.On Sunday, 13 March 2022 at 08:23:52 UTC, Dom DiSc wrote:`foreach` **does** introduce a new scope I believe it is `static foreach` that **doesn't** introduce a new scope(hence why you see `static foreach(){{ /*code/* }}` style code sometimesSo any new feature is here totally superfluous IMHO.And btw. foreach doesn't even introduce a new scope, so you can't get your import more local than in my version, no matter what new syntax you invent.
Mar 15 2022
On Tuesday, 15 March 2022 at 10:25:54 UTC, bauss wrote:
```d
scope static foreach (...) { ... }
or
static foreach (...) scope { ... }
```
Would've been much cleaner.
```d
{
static foreach(...)
{
}
}
```
Mar 15 2022
On Tuesday, 15 March 2022 at 13:53:51 UTC, Andrea Fontana wrote:On Tuesday, 15 March 2022 at 10:25:54 UTC, bauss wrote:The whole point is to avoid the extra brackets and/or the extra unnecessary indentation.```d scope static foreach (...) { ... } or static foreach (...) scope { ... } ``` Would've been much cleaner.```d { static foreach(...) { } } ```
Mar 15 2022
On Sunday, 13 March 2022 at 08:23:52 UTC, Dom DiSc wrote:
Locality can be overdone. I think this would suffice:
```d
if (Values.length != 0)
{
import std.functional : binaryFun;
foreach (uint i, ref v; values)
if (binaryFun!pred(value, v)) return i + 1;
return 0;
}
```
So any new feature is here totally superfluous IMHO.
There are three considerations here:
- Functionality - What you can do
- Performance - How fast you can do it
- Readability - How easy it is to see what you're doing
Your argument about it being superfluous addresses Functionality
and Performance, but not Readability. And the feature is not
entirely superfluous with regards to Functionality and
Performance either. But I'll address those later.
Regarding performance in this particular case, I agree with you.
When you import a symbol as locally as is done in the example
above, the compiler find its definition quickly enough. The only
slow contender in this case is `imported` from object.d:
```d
if (imported!"std.functional".binaryFun!pred(value, v)) return
i + 1;
```
Regarding functionality, the functionality between having a
separate import statement and the inline one is the similar in
ordinary code. Both the statement and the inline bring in the
symbol and then use it once.
It should be pointed out that if you wanted to use the symbol
again in the same scope, the separate import statement is
superior. This is a deficiency of the proposed single-use imports
that I will address below.
But we have to consider readability.
Ideally, code is written in a way which allows a programmer to
see clearly what is important, without having to be distracted by
what is not important. Unimportant code which takes too prominent
a place constitutes an undesirable distraction — in the recent
thread about Exceptions vs. other Error Handling, the chief fear
with Error Codes is that they make unimportant code too prominent.
Because symbols must be imported to be used, programmers have
gotten used to seeing what is imported blasted like a trumpet at
the top of their scope or module.
```d
{
// Look at me! I must be important!
import std.functional : binaryFun;
...
}
```
But the actual importance of any given imported symbol depends
greatly on the specific symbol and the context. Certainly, the
readability of some code is not diminished by having notable
symbols be prominently announced before they are used. But just
as often, the imported functionality is so ordinary that it is
nothing but a distraction having to see it promoted so blatantly.
Therefore, being able to inline imports, and make them as
innocuous as possible, will enable the programmer to indicate how
significant each symbol actually is, instead of forcing them all
into the limelight.
Local imports, even though they can force unimportant symbols
into the limelight, have been widely adopted in D for perhaps two
reasons — performance and readability. Performance, because of
shortened lookup times. And readability, because you can more
easily find the source of a specified symbol the closer its
definition is to its usage.
But local imports have also come at a cost to readability, in the
sense that they are a visual distraction. We can say, at least in
the case of module level imports, that you can just use their
symbols without much
[fanfare](https://en.wikipedia.org/wiki/Fanfare).
------------
We have to address functionality. It was argued above that inline
imports as a feature are "totally superfluous." Even apart from
readability, that is not true. Particularly, with regards to
template constraints, they are necessary in order to be able to
use local imports at all.
This was written about with a level of rigor suited to a serious
academic paper in Andrei Alexandrescu's
[DIP1005](https://github.com/dlang/DIPs/blob/master/DIPs/other/DIP1005.md).
That proposal suggests the following syntax to allow inline imports at the
template level:
```d
with (import std.meta : allSatisfy)
with (import std.range : ElementEncodingType)
with (import std.traits : hasIndirections, isDynamicArray,
isIntegral)
auto uninitializedArray(T, I...)(I sizes) nothrow system
if (isDynamicArray!T && allSatisfy!(isIntegral, I) &&
hasIndirections!(ElementEncodingType!T))
{
...
}
```
Now let's see how it would look with my proposed long-form
syntax. Since the improved shorter form of the syntax
(`:modname:symbol`) now uses two colons, it makes sense to
retroactively make the original longer form reflect that. Let it
be an example of the [Mandela
Effect](https://www.entitymag.com/mandela-effect-examples/). Let
no one remember that I ever suggested doing anything else. :-)
```d
auto uninitializedArray(T, I...)(I sizes) nothrow system
if (import:std.traits:isDynamicArray!T &&
import:std.meta:allSatisfy!(import:std.traits:isIntegral, I)
&&
import:std.traits:hasIndirections!(import:std.range:ElementEncodingType!T))
{
...
}
```
This form is just as good if not better than `with(import x.y :
z)`, and it can be used anywhere.
--
An additional point of functionality regarding inline imports is
that you can import a symbol in a [function
contract](https://dlang.org/spec/function.html#contracts) without
having to use the verbose form. So the clunky:
```d
int func(A a, B b)
in
{
import std.algorithm.comparison : cmp;
assert(cmp(a,b) < 0);
}
do
{
// function body
}
```
...becomes:
```d
int func(A a, B b)
in (:std.algorithm.comparison: cmp(a, b) < 0)
{
// function body
}
```
------------------
The feature looks pretty good. The syntax looks good. But the one
remaining concern is reusability. If inline imports are designed
to be used exactly once without any further effect, many common
use cases will find them too burdensome.
```d
unittest {
assert(:std.traits: sometest(myFunc, [1,2,3]));
// you mean I have to import it every single time?
assert(sometest(myFunc, [4,5,6])); // error: undefined symbol
`sometest`
assert(sometest(myFunc, [7,8,9])); // error: undefined symbol
`sometest`
// etc.
}
```
What we really want is to be able to import the symbol inline,
and then have it available as a regular symbol for the rest of
the scope. The implementation of this feature could be as simple
as a statement-level syntactic rewrite. So the above would be
rewritten to:
```d
unittest {
import std.traits : sometest; // <-- inline import rewritten
to
assert(/* :std.traits: */ sometest(myFunc, [1,2,3]));
// now we don't have to keep importing it
assert(sometest(myFunc, [4,5,6]));
assert(sometest(myFunc, [7,8,9]));
// etc.
}
```
What are the caveats of such a rewrite? Well, we would have to
deal with the extremely rare case of a valid symbol changing its
meaning due to a subsequent import in the same statement. Since
defining the same variable twice within a function rightfully
produces an error, this would only happen with symbols defined
outside the function:
```d
// a.d
module a;
int x = 4;
----------
// main.d
int x = 3;
void main() {
{
assert(x == 3);
// import a : x; // <-- this is where the rewrite occurs
assert(x + :a: x + x == 4 + 4 + 4);
assert(x == 4);
}
assert(x == 3);
}
```
The above code already compiles and runs as long as we rewrite
the inline import to included the commented out line. Such a
simple rewrite may be so easy to implement as a feature — and the
alternative, more complex interpretation (`x + :a: x + x == 3 + 4
+ 4`) so ill-conceived with regard to any coding style that could
possibly be considered allowable — that the language can simply
be specified to say that the above, statement-level syntactic
rewrite is how inline imports work.
--
Finally, we have to consider the "scope" of symbols imported by
template constraints and other parts of the function signature.
Symbols which are imported in the constraints, contracts, or just
the regular signature (assuming you can import basic types there)
should be made available for all the other parts of the function
to access. Let's give a name to this greater space into which all
these symbols are imported. Let's call it the "metascope" of the
function.
This simply means that inline imports are designed so that you
don't have to import any symbol twice for the same function. So
for example with this signature from phobos, the first import of
`isInputRange` should put it into the function's metascope so
there's no need to import it again:
```d
auto cmp(R1, R2)(R1 r1, R2 r2)
if (:std.range: isInputRange!R1 && /* :std.range:(<-- no need) */
isInputRange!R2)
{ ... }
```
Mar 15 2022









=?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> 