www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - post 2.071 mixin template & import rules

reply captaindet <2krnk gmx.net> writes:
the way import declarations work has changed quite a bit with 2.071. two 
aspects have been written up nicely by steve schveighoffer ( 
http://www.schveiguy.com/blog/2016/03/import-changes-in-d-2-071 ). 
breaking as they might be for some, they are (a) a mere enforcement of 
the rules as they were always set out and (b) a change in look-up order 
preventing hijacking/overshadowing.

it appears that there had been an even more radical change as well with 
respect to the way mixin templates work. this has not been properly 
communicated yet. at least i could not find a write-up and a related 
thread conveyed rather guesswork than knowledge. ( 
https://forum.dlang.org/post/nl2bgi$2oim$1 digitalmars.com )

from this thread i tried to distill the gist below... so that if my 
understanding is confirmed by the language devs, it may serve as an 
explanation of changes complementary to steve's blog post.

----

mixin templates - https://dlang.org/spec/template-mixin.html :
"A TemplateMixin takes an arbitrary set of declarations from the body of 
a TemplateDeclaration and inserts them into the current context."

as of the the specs https://dlang.org/spec/module.html imports are 
declarations too and before 2.071 the mixin template design spec above 
would work for them just the same. as in:

```
mixin template AddImp (){
	import core.thread;
}
mixin AddImp;
```

this would import core.thread just alright into the current scope. 
regardless where the instantiation happens, module level as well as 
within classes etc. (note that the mixin template definition can be in 
another module and itself be constructed by more mixin templates or 
string mixins.)

especially if

```
module a;
mixin template AddImp (){
	public import core.thread;
}
```

and

```
module b;
mixin AddImp;
```

ie on module level, then in module b core.thread as a whole would be 
visible/accessible/imported.

apparently starting with 2.071 import declarations are not treated as 
declarations in the sense of mixin templates anymore. meaning that whole 
module imports (private and public) in mixin template definitions are 
not inserted into the instantiating scope anymore. neither if 
instantiated on module level, nor if in a class etc. it is not that the 
look-up order has changed for them, they are blatantly ignored now.

(and this is what i am not happy with it. it would be more consisting if 
the imports would be inserted in the current scope just as they were 
before but with the local definitions having precedence - similar to how 
issue 10378 was fixed - just as it would be if you actually wrote 
"import core.thread;" instead of "mixin AddImp;" also, it would not 
leave me with a ton of code that needs rewriting.)

on the other hand, if not a whole module is imported but individual 
symbols via selective import, it still works the same as before. eg:

```
module a;
mixin template AddImp (){
	public import core.thread : Thread;
}
```

and

```
module b;
mixin AddImp;
```

will make Thread available in all of module b.

----

please correct my view of things if i got it wrong.

thanks

/det
Jun 30 2016
next sibling parent qznc <qznc web.de> writes:
On Friday, 1 July 2016 at 05:42:30 UTC, captaindet wrote:
 it appears that there had been an even more radical change as 
 well with respect to the way mixin templates work. this has not 
 been properly communicated yet. at least i could not find a 
 write-up and a related thread conveyed rather guesswork than 
 knowledge. ( 
 https://forum.dlang.org/post/nl2bgi$2oim$1 digitalmars.com )
The question is: Was it intentional? Imho, it is weird that template mixin have different behavior than modules with respect to import visibility. I don't see a reason, why a public import should not be exported.
Jul 01 2016
prev sibling parent Steven Schveighoffer <schveiguy yahoo.com> writes:
On 7/1/16 1:42 AM, captaindet wrote:

 apparently starting with 2.071 import declarations are not treated as
 declarations in the sense of mixin templates anymore. meaning that whole
 module imports (private and public) in mixin template definitions are
 not inserted into the instantiating scope anymore. neither if
 instantiated on module level, nor if in a class etc. it is not that the
 look-up order has changed for them, they are blatantly ignored now.
I understand this position. Note that with the new import rules, importing a module wholesale into a scope is not nearly as damaging as before (where everything overrode locals and even module symbols). In most of the changes, the import succeeds, but is just not selected first to avoid hijacking. In this case, it looks like the import is simply ignored. That doesn't make a whole lot of sense. Even when the import is intended to add a specific member to the function, this doesn't help. e.g.: a.d: module a; import std.stdio; struct Foo { int x; void fun() { writeln("fun ", x); } } void gun(Foo f) { writeln("gun ", f.x); } b.d: module b; mixin template AddImp (){ import a; Foo f; } c.d: import b; struct Bar { mixin AddImp; void bar() { f.fun(); f.gun(); // worked before, but now fails! } } void main() { Bar b; b.bar; } What is the point of disallowing f.gun()? It's literally part of the intended interface of Foo, why can't that be had? I see no reason to disallow this. If I defined a gun(Foo f) in c.d, it would override that. There's no hijacking possible. In order to properly write AddImp, I'd have to find all the possible ways that Foo could be used given UFCS, and import those as selected imports. This is not how it should be IMO. The blunt fix would be I guess to public import a at module level, but that's opening up all importers of b to a's code. -Steve
Jul 01 2016