www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - mixin module template -> undefined identifier

reply Robert Schadek <realburner gmx.de> writes:
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
Oct 03 2013
next sibling parent reply "David Nadlinger" <code klickverbot.at> writes:
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
Oct 03 2013
next sibling parent reply Robert Schadek <realburner gmx.de> writes:
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.
Oct 03 2013
next sibling parent reply "David Nadlinger" <code klickverbot.at> writes:
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
Oct 03 2013
parent Robert Schadek <realburner gmx.de> writes:
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.
Oct 04 2013
prev sibling parent "Dicebot" <public dicebot.lv> writes:
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)
Oct 04 2013
prev sibling parent Kenji Hara <k.hara.pg gmail.com> writes:
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 instantiati=
ng
 Yes, this is indeed very much by design =E2=80=93 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 =C2=BBmixin("T.fun()")=C2=AB). I'm aware that the situation wher=
e 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
Oct 03 2013
prev sibling parent reply "Dicebot" <public dicebot.lv> writes:
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
Oct 04 2013
parent Robert Schadek <realburner gmx.de> writes:
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.
Oct 04 2013