Thread overview
mixin module template -> undefined identifier
Oct 03, 2013
Robert Schadek
Oct 03, 2013
David Nadlinger
Oct 03, 2013
Robert Schadek
Oct 04, 2013
David Nadlinger
Oct 04, 2013
Robert Schadek
Oct 04, 2013
Dicebot
Oct 04, 2013
Kenji Hara
Oct 04, 2013
Dicebot
Oct 04, 2013
Robert Schadek
October 03, 2013
I have some found some irregular behavior when using mixins with template and modules. If a aggregation is defined in the same module it is found. If the aggregation is defined in another module it fails. And I wonder if this is be design. For comparison see the code below.

// file: moduleA.d

module A;

public int func(T)() {
    return mixin(T.stringof ~ ".fun()");
}

struct Bar {
    static int fun() {
        return 2;
    }
}

unittest {
    static assert(func!Bar() == 2);
}


// file: moduleB.d

import A;

struct Foo {
    static int fun() {
        return 1;
    }
}

void main() {
    assert(func!Foo() == 1);
}

dmd moduleA.d moduleB.d -ofmix -unittest
moduleA.d(4): Error: undefined identifier Foo
moduleB.d(10): Error: template instance A.func!(Foo) error instantiating
October 03, 2013
On Thursday, 3 October 2013 at 17:52:13 UTC, Robert Schadek wrote:
> // file: moduleA.d
>
> module A;
>
> public int func(T)() {
>     return mixin(T.stringof ~ ".fun()");
> }
>
> […]
>
> dmd moduleA.d moduleB.d -ofmix -unittest
> moduleA.d(4): Error: undefined identifier Foo
> moduleB.d(10): Error: template instance A.func!(Foo) error instantiating

Yes, this is indeed very much by design – A does not import B, so there is no reason why the name "Foo" should exist in A.

To access the template parameter, just use it directly in the mixin (as in »mixin("T.fun()")«). I'm aware that the situation where you actually stumbled over this is probably a bit more complex, but in my experience an equivalent rewrite can almost always be performed quite easily once you have wrapped your head around the concept.

Oh, and for those of you keeping track, this is another example supporting my stance that using "stringof" for code generation is (almost) always a bad idea. The fact that experienced D coders seem to run into this trap quite frequently, judging from the fact that is by far not the first NG thread on this topic, seems to suggest that we should address this with a big red warning in the documentation, probably where string mixins are discussed. (The recently merged pull request warning about .stringof use is a first step, albeit it does so for a different reason.)

David
October 03, 2013
On 10/03/2013 08:10 PM, David Nadlinger wrote:
> On Thursday, 3 October 2013 at 17:52:13 UTC, Robert Schadek wrote:
>>
>> dmd moduleA.d moduleB.d -ofmix -unittest
>> moduleA.d(4): Error: undefined identifier Foo
>> moduleB.d(10): Error: template instance A.func!(Foo) error instantiating
>
> Yes, this is indeed very much by design – A does not import B, so there is no reason why the name "Foo" should exist in A.
Yes, it does not exists in the module but func is a template and I was under the impression symbols would be seen when instantiated. I mean the error starts with A.func!(Foo) error instantiating.
>
> To access the template parameter, just use it directly in the mixin (as in »mixin("T.fun()")«). I'm aware that the situation where you actually stumbled over this is probably a bit more complex, but in my experience an equivalent rewrite can almost always be performed quite easily once you have wrapped your head around the concept.
Not as easy to fix this as I have a library that generates me sqlite code at compile time which I than mixin to have as good as handwritten code. I just found it odd that it works if I instantiate the template from the same module.


October 04, 2013
2013/10/4 Robert Schadek <realburner@gmx.de>

> On 10/03/2013 08:10 PM, David Nadlinger wrote:
> > On Thursday, 3 October 2013 at 17:52:13 UTC, Robert Schadek wrote:
> >>
> >> dmd moduleA.d moduleB.d -ofmix -unittest
> >> moduleA.d(4): Error: undefined identifier Foo
> >> moduleB.d(10): Error: template instance A.func!(Foo) error instantiating
> >
> > Yes, this is indeed very much by design – A does not import B, so there is no reason why the name "Foo" should exist in A.
> Yes, it does not exists in the module but func is a template and I was under the impression symbols would be seen when instantiated. I mean the error starts with A.func!(Foo) error instantiating.
> >
> > To access the template parameter, just use it directly in the mixin (as in »mixin("T.fun()")«). I'm aware that the situation where you actually stumbled over this is probably a bit more complex, but in my experience an equivalent rewrite can almost always be performed quite easily once you have wrapped your head around the concept.
> Not as easy to fix this as I have a library that generates me sqlite code at compile time which I than mixin to have as good as handwritten code. I just found it odd that it works if I instantiate the template from the same module.
>

Using built-in 'stringof' property for code generation won't work in general. Instead:

public int func(T)() {
    return mixin("T" ~ ".fun()");
}

Kenji Hara


October 04, 2013
On Thursday, 3 October 2013 at 18:39:48 UTC, Robert Schadek wrote:
> Yes, it does not exists in the module but func is a template and I was
> under the impression symbols would be seen when instantiated.

No. D doesn't have something like C++'s ADL where the template arguments lead to additional names being introduced into the scope of the template body. This is by design.

> I mean the
> error starts with A.func!(Foo) error instantiating.

Sorry, I don't quite get what you mean here. The error is just a follow-up to the previous one, as the inability to look up Foo caused an error while instantiating that template.

> Not as easy to fix this as I have a library that generates me sqlite
> code at compile time which I than mixin to have as good as handwritten
> code. I just found it odd that it works if I instantiate the template
> from the same module.

Maybe you can elaborate a bit on how the problem occurs in that context? As I said, I've found that usually it is possible to come up with a design at least as pretty (or even prettier) but doesn't rely on stringof trickery if one just stares at the problem long enough. ;)

David
October 04, 2013
By spec name resolution for templates happens in declaration scope. Mixin templates are only exception.

If referencing symbol from other module during code gen is a unavoidable necessity, you should use instrospection on `T` and add its module into code gen as template-local import (something like https://github.com/rejectedsoftware/vibe.d/blob/master/source/vibe/http/restutil.d#L341)
October 04, 2013
P.S. I have tried contacting you in context of std.logger, is mail address mentioned on github valid one? If not, please ping me via public.dicebot.lv
October 04, 2013
On 10/04/2013 09:07 AM, Dicebot wrote:
> P.S. I have tried contacting you in context of std.logger, is mail address mentioned on github valid one? If not, please ping me via public.dicebot.lv
Yes it is, strange. Try the one I use here.
October 04, 2013
On 10/04/2013 04:36 AM, David Nadlinger wrote:
> Maybe you can elaborate a bit on how the problem occurs in that context? As I said, I've found that usually it is possible to come up with a design at least as pretty (or even prettier) but doesn't rely on stringof trickery if one just stares at the problem long enough. ;)

I will try to find a way around.