www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Templates and stringof...

reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
  While working on bitfields code I've found a unique scenario 
that poses some annoyances when generating the code.


template XYZ(alias x) {
     enum XYZ = x.stringof ~ "=100;";
}

struct I { int i;}

I i_num;
int n;

mixin(XYZ!(i_num.i)); //cannot find variable i
mixin(XYZ!(n));

the mixins become:
i=100;
n=100;


  Now, how do I get the template's stringof to print out 'i_num.i' 
and not 'i'?
Aug 03 2012
next sibling parent "David Nadlinger" <see klickverbot.at> writes:
On Friday, 3 August 2012 at 21:02:22 UTC, Era Scarecrow wrote:
  Now, how do I get the template's stringof to print out 
 'i_num.i' and not 'i'?

You don't. Using .stringof in conjunction with string mixins is The Wrong Thing (tm) in virtually all cases. What do you want to achieve? Why can't you pass a string instead? David
Aug 03 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Friday, 3 August 2012 at 21:19:08 UTC, David Nadlinger wrote:
 On Friday, 3 August 2012 at 21:02:22 UTC, Era Scarecrow wrote:
 Now, how do I get the template's stringof to print out 
 'i_num.i' and not 'i'?

You don't. Using .stringof in conjunction with string mixins is The Wrong Thing (tm) in virtually all cases. What do you want to achieve? Why can't you pass a string instead?

Because a string doesn't hold it's type information for size checking. int = 4 bytes or 32 bits string = ???? It also checks for unsuitable types like structs and floats; can't do that with strings.
Aug 03 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 8/3/12, Era Scarecrow <rtcvb32 yahoo.com> wrote:
   Now, how do I get the template's stringof to print out 'i_num.i'
 and not 'i'?

Courtesy of Philippe Sigaud, slightly edited to my style: /** Return the fully qualified name of a symbol. Implemented by Philippe Sigaud in the D Templates book. See https://github.com/PhilippeSigaud/D-templates-tutorial */ template ScopedName(alias a) { // does it have a parent? static if (__traits(compiles, __traits(parent, a))) { // If yes, get the name and recurse enum ScopedName =3D ScopedName!(__traits (parent, a)) ~ "." ~ NameO= f!(a); } else { // if not, it=92s a module name. Stop there. enum ScopedName =3D NameOf!a; } } template NameOf(alias a) { enum string NameOf =3D __traits(identifier, a); } template XYZ(alias x) { enum XYZ =3D ScopedName!x ~ "=3D100;"; }
Aug 03 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 8/4/12, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:
 On 8/3/12, Era Scarecrow <rtcvb32 yahoo.com> wrote:
   Now, how do I get the template's stringof to print out 'i_num.i'
 and not 'i'?


Ahh crap, it doesn't return the *instance* name. Sorry!! Maybe there can be a fix though, I'll give it a try..
Aug 03 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Friday, 3 August 2012 at 22:18:25 UTC, Andrej Mitrovic wrote:
 On 8/4/12, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:
 On 8/3/12, Era Scarecrow <rtcvb32 yahoo.com> wrote:
   Now, how do I get the template's stringof to print out 
 'i_num.i'
 and not 'i'?


Ahh crap, it doesn't return the *instance* name. Sorry!! Maybe there can be a fix though, I'll give it a try..

Mmmm worse comes to worse i can do a mixin, which generates the text into it's non-text verision and passes both to my template which then does it's appropriate checks. Seems like an ugly hack though (to get this done). Why not have another method of fullpathStringof or something similar? Then again if this is one of the few cases that could benefit from it, then maybe we should make it ugly so no one else will use it.
Aug 03 2012
prev sibling next sibling parent "David Nadlinger" <see klickverbot.at> writes:
On Friday, 3 August 2012 at 21:33:35 UTC, Era Scarecrow wrote:
  Because a string doesn't hold it's type information for size 
 checking.

  int = 4 bytes or 32 bits
  string = ????

Just emit the check into the code you generate.
  It also checks for unsuitable types like structs and floats; 
 can't do that with strings.

Just emit the check into the code you generate. David
Aug 03 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 8/4/12, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:
 On 8/3/12, Era Scarecrow <rtcvb32 yahoo.com> wrote:
   Now, how do I get the template's stringof to print out 'i_num.i'
 and not 'i'?

Courtesy of Philippe Sigaud, slightly edited to my style:

In fact, this should really be put into Phobos so everyone can benefit rather than implementing this internally as a private template of bitmanip.
Aug 03 2012
prev sibling next sibling parent "David Nadlinger" <see klickverbot.at> writes:
On Friday, 3 August 2012 at 22:23:23 UTC, Era Scarecrow wrote:
  Seems like an ugly hack though (to get this done). Why not 
 have another method of fullpathStringof or something similar? 
 Then again if this is one of the few cases that could benefit 
 from it, then maybe we should make it ugly so no one else will 
 use it.

This can't work in general. What should such a function return? The fully qualified name, i.e. including packages and modules? What is if the referred to entity is a nested function/local variable? What is if it is defined in a module which is not imported in the place where the string is mixed in? Regarding Philippe Sigaud's stuff: He has done a lot of great work, but exactly this use of strings is why some of his template constructions are not usable in the real world. Again, using .stringof in conjunction with string mixins is almost never a good idea. Please trust me on this, I've done quite a bit of metaprogramming-heavy projects, and there are always ways around this, which are often more elegant as well. David
Aug 03 2012
prev sibling next sibling parent "David Nadlinger" <see klickverbot.at> writes:
On Friday, 3 August 2012 at 22:44:28 UTC, Andrej Mitrovic wrote:
 On 8/4/12, Andrej Mitrovic <andrej.mitrovich gmail.com> wrote:
 Courtesy of Philippe Sigaud, slightly edited to my style:

In fact, this should really be put into Phobos so everyone can benefit rather than implementing this internally as a private template of bitmanip.

No, it shouldn't be. There are almost no legit use cases for it, and having it in the library encourages abuse of string mixins/stringof in cases like this one.
Aug 03 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Friday, 3 August 2012 at 22:47:52 UTC, David Nadlinger wrote:
 On Friday, 3 August 2012 at 22:23:23 UTC, Era Scarecrow wrote:
 Seems like an ugly hack though (to get this done). Why not 
 have another method of fullpathStringof or something similar? 
 Then again if this is one of the few cases that could benefit 
 from it, then maybe we should make it ugly so no one else will 
 use it.

This can't work in general. What should such a function return? The fully qualified name, I.e. including packages and modules? What is if the referred to entity is a nested function/local variable? What is if it is defined in a module which is not imported in the place where the string is mixed in?

I would think, the exact 'text' of the way the variable was called, in my example it would be "inum.i", and since it would be at the local level (where the mixin was called) it should have access to everything that it did at that time.
 Regarding Philippe Sigaud's stuff: He has done a lot of great 
 work, but exactly this use of strings is why some of his 
 template constructions are not usable in the real world. Again, 
 using .stringof in conjunction with string mixins is almost 
 never a good idea. Please trust me on this, I've done quite a 
 bit of metaprogramming-heavy projects, and there are always 
 ways around this, which are often more elegant as well.

I have limited experience making and using templates, so I'll have to believe you; But it still seems like there should be a much better way than an uber-ugly work around. One of the reasons I want to use an alias vs a string, is so I can use the constraints the way they are suppose to be.
Aug 03 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Friday, 3 August 2012 at 22:50:54 UTC, David Nadlinger wrote:
 On Friday, 3 August 2012 at 22:44:28 UTC, Andrej Mitrovic wrote:
 In fact, this should really be put into Phobos so everyone can 
 benefit rather than implementing this internally as a private 
 template of bitmanip.

No, it shouldn't be. There are almost no legit use cases for it, and having it in the library encourages abuse of string mixins/stringof in cases like this one.

Then doesn't it seem like we're missing a potentially important piece of the puzzle for mixins and templates? very likely my modified template will include you including the same variable twice, but if someone gets lazy then it may not work. mixin(bitfieldsOn!("SomeVariable", SomeVariable, /*stuff*/)); // or mixin(bitfieldsOn!("SomeVariable", variable type, /*stuff*/)); But if it comes to it, what if they use auto or point to something else just to make it shut up? Constraints will let it pass but the code will pop up with errors that may not be reasonably readable. long l; float fl; mixin(bitfieldsOn!("fl", l, /*stuff*/)); //by name, typo or lazy //or mixin(bitfieldsOn!("fl", auto, /*stuff*/)); //explicit type, lazy or lying Now the checks pass but the compile code works wrong. True I can add asserts as part of the output code, but as mentioned hopefully the constraints could do that work, plus adding extra checks as part of a mixin seems a little... excessive. Let's assume we use 'localStringof' or 'callingStringof' and that it returns the string of how the variable is called/referenced; Give me some examples how it would be abused or used wrongly? Aliased variables are pretty much perfect forwarded in templates (Unless my understanding is off) so they would carry that information forward.
Aug 03 2012
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
--00248c71184b739c2d04c66bff2d
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

Le 4 ao=C3=BBt 2012 00:50, "David Nadlinger" <see klickverbot.at> a =C3=A9c=
rit :
 On Friday, 3 August 2012 at 22:23:23 UTC, Era Scarecrow wrote:
  Seems like an ugly hack though (to get this done). Why not have another


of the few cases that could benefit from it, then maybe we should make it ugly so no one else will use it.
 This can't work in general. What should such a function return? The fully

referred to entity is a nested function/local variable? What is if it is defined in a module which is not imported in the place where the string is mixed in?
 Regarding Philippe Sigaud's stuff: He has done a lot of great work, but

not usable in the real world. Again, using .stringof in conjunction with string mixins is almost never a good idea. FWIW, I agree with David that using .stringof is a last resort and can lead to nasty bugs. .stringof has a sometime incoherent behavior (I remember it showing the entire code inside a delegate literal) But then, the code shown upstream do *not* use .stringof. It uses __traits(parent, ) and __traits(qualifier, ), which are much more 'modern' and well-behaved. For std.reflection that Andrei proposed 2 weeks ago, I feel the internal code will contain many __traits() calls. Nothing to be done about it. __traits is *the* way compile-time introspection is done in D. --00248c71184b739c2d04c66bff2d Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <p><br> Le 4 ao=C3=BBt 2012 00:50, &quot;David Nadlinger&quot; &lt;<a href=3D"mailt= o:see klickverbot.at">see klickverbot.at</a>&gt; a =C3=A9crit=C2=A0:<br> &gt;<br> &gt; On Friday, 3 August 2012 at 22:23:23 UTC, Era Scarecrow wrote:<br> &gt;&gt;<br> &gt;&gt; =C2=A0Seems like an ugly hack though (to get this done). Why not h= ave another method of fullpathStringof or something similar? Then again if = this is one of the few cases that could benefit from it, then maybe we shou= ld make it ugly so no one else will use it.<br> &gt;<br> &gt;<br> &gt; This can&#39;t work in general. What should such a function return? Th= e fully qualified name, i.e. including packages and modules? What is if the= referred to entity is a nested function/local variable? What is if it is d= efined in a module which is not imported in the place where the string is m= ixed in?<br> &gt;<br> &gt; Regarding Philippe Sigaud&#39;s stuff: He has done a lot of great work= , but exactly this use of strings is why some of his template constructions= are not usable in the real world. Again, using .stringof in conjunction wi= th string mixins is almost never a good idea. <br> </p> <p>FWIW, I agree with David that using .stringof is a last resort and can l= ead to nasty bugs. .stringof has a sometime incoherent behavior (I remember= it showing the entire code inside a delegate literal)</p> <p>But then, the code shown upstream do *not* use .stringof.</p> <p>It uses __traits(parent, ) and __traits(qualifier, ), which are much mor= e &#39;modern&#39; and well-behaved.</p> <p>For std.reflection that Andrei proposed 2 weeks ago, I feel the internal= code will contain many __traits() calls. Nothing to be done about it. __tr= aits is *the* way compile-time introspection is done in D.</p> --00248c71184b739c2d04c66bff2d--
Aug 04 2012
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, August 04, 2012 09:57:36 Philippe Sigaud wrote:
 For std.reflection that Andrei proposed 2 weeks ago, I feel the internal
 code will contain many __traits() calls. Nothing to be done about it.
 __traits is *the* way compile-time introspection is done in D.

That and std.traits. Between those two and the power of is expressions, that's where the ability to do compile-time introspection comes from. - Jonathan M Davis
Aug 04 2012
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
--20cf3074b9d6356dc804c66c2467
Content-Type: text/plain; charset=UTF-8

"Era Scarecrow" <rtcvb32 yahoo.com>

  Then doesn't it seem like we're missing a potentially important piece of

include you including the same variable twice, but if someone gets lazy then it may not work.
  mixin(bitfieldsOn!("SomeVariable", SomeVariable, /*stuff*/));
  // or
  mixin(bitfieldsOn!("SomeVariable", variable type, /*stuff*/));

Hmm. You can ask for just the name as a string (so, qualified or not, as the user wish) and include a test for the type of the passed name. inside bitfieldsOn: mixin(" static if is(typeof("~name~")) alias typeof(" ~ name ~ ") NameType; else static assert(false, `bad name given to bitfieldsOn:"~name~".`); ") Untested, I'm on a pad right now. --20cf3074b9d6356dc804c66c2467 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <p><br> &quot;Era Scarecrow&quot; &lt;<a href=3D"mailto:rtcvb32 yahoo.com">rtcvb32 = yahoo.com</a>&gt;</p> <p>&gt; =C2=A0Then doesn&#39;t it seem like we&#39;re missing a potentially= important piece of the puzzle for mixins and templates? very likely my mod= ified template will include you including the same variable twice, but if s= omeone gets lazy then it may not work.<br> &gt;<br> &gt; =C2=A0mixin(bitfieldsOn!(&quot;SomeVariable&quot;, SomeVariable, /*stu= ff*/));<br> &gt; =C2=A0// or<br> &gt; =C2=A0mixin(bitfieldsOn!(&quot;SomeVariable&quot;, variable type, /*st= uff*/));</p> <p>Hmm. You can ask for just the name as a string (so, qualified or not, as= the user wish) and include a test for the type of the passed name.</p> <p>inside bitfieldsOn:</p> <p>=C2=A0=C2=A0=C2=A0 mixin(&quot;<br> static if is(typeof(&quot;~name~&quot;))<br> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 alias typeof(&quot; ~ name ~ &qu= ot;) NameType;<br> =C2=A0=C2=A0=C2=A0 else<br> =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0 static assert(false, `bad name g= iven to bitfieldsOn:&quot;~name~&quot;.`);<br> &quot;) </p> <p>Untested, I&#39;m on a pad right now.<br> </p> --20cf3074b9d6356dc804c66c2467--
Aug 04 2012
prev sibling next sibling parent "David Nadlinger" <see klickverbot.at> writes:
On Saturday, 4 August 2012 at 08:06:31 UTC, Jonathan M Davis 
wrote:
 On Saturday, August 04, 2012 09:57:36 Philippe Sigaud wrote:
 For std.reflection that Andrei proposed 2 weeks ago, I feel 
 the internal
 code will contain many __traits() calls. Nothing to be done 
 about it.
 __traits is *the* way compile-time introspection is done in D.

That and std.traits. Between those two and the power of is expressions, that's where the ability to do compile-time introspection comes from.

There is nothing wrong about __traits, just about .stringof resp. __traits(identifier) in conjunction with string mixins. David
Aug 04 2012
prev sibling next sibling parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Saturday, 4 August 2012 at 07:57:46 UTC, Philippe Sigaud wrote:
 FWIW, I agree with David that using .stringof is a last resort 
 and can lead to nasty bugs. .stringof has a sometime incoherent 
 behavior (I remember it showing the entire code inside a 
 delegate literal)

 But then, the code shown upstream do *not* use .stringof.

 It uses __traits(parent, ) and __traits(qualifier, ), which are 
 much more 'modern' and well-behaved.

 For std.reflection that Andrei proposed 2 weeks ago, I feel the 
 internal code will contain many __traits() calls. Nothing to be 
 done about it. __traits is *the* way compile-time introspection 
 is done in D.

If traits will work, then that's what we go with. I've already got a workaround for what I need, a template creating a mixin, that you use a mixin on to make the bitfields; not pretty, but it will do the job; at least until a better option shows itself, preferably in a template in std.traits I can use and not go lower-level than I have to. Sorry if I've taken up unnecessary time.
Aug 04 2012
prev sibling next sibling parent "David Nadlinger" <see klickverbot.at> writes:
On Saturday, 4 August 2012 at 07:57:46 UTC, Philippe Sigaud wrote:
 It uses __traits(parent, ) and __traits(qualifier, ), which are 
 much more
 'modern' and well-behaved.

An example of what I mean: Try this with your CurryTemplate from dranges: --- import dranges.templates; template Foo(A, B) { pragma(msg, A.stringof, " ", B.stringof); } alias CurryTemplate!Foo FooCurried; alias FooCurried!int FooInt; alias FooInt!string Test; --- David
Aug 04 2012
prev sibling next sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sat, Aug 4, 2012 at 10:25 AM, David Nadlinger <see klickverbot.at> wrote:

 An example of what I mean: Try this with your CurryTemplate from dranges:

 ---
 import dranges.templates;

 template Foo(A, B) {
     pragma(msg, A.stringof, " ", B.stringof);
 }

 alias CurryTemplate!Foo FooCurried;
 alias FooCurried!int FooInt;
 alias FooInt!string Test;

Oh, I completely forgot this. Nice code, if I may say so myself :) But yes, having identifiers going back and forth between modules is difficult. I didn't realize this in 2009, while most of dranges was written. Now, since I regularly need to have a template work on local identifiers, I tend to use mixins much more than in dtemplates.
Aug 04 2012
prev sibling next sibling parent "David Nadlinger" <see klickverbot.at> writes:
On Saturday, 4 August 2012 at 11:29:36 UTC, Philippe Sigaud wrote:
 Oh, I completely forgot this. Nice code, if I may say so myself 
 :)

Huh? It's broken, precisely because of the use of __traits(identifier, …) in combination with string mixins. The example doesn't compile. David
Aug 04 2012
prev sibling parent Philippe Sigaud <philippe.sigaud gmail.com> writes:
On Sat, Aug 4, 2012 at 1:35 PM, David Nadlinger <see klickverbot.at> wrote:
 On Saturday, 4 August 2012 at 11:29:36 UTC, Philippe Sigaud wrote:
 Oh, I completely forgot this. Nice code, if I may say so myself :)

Huh? It's broken, precisely because of the use of __traits(identifier, =

 combination with string mixins. The example doesn't compile.

Yes, I know :) I does desmontrate your point, you convinced me. But the code was from a long time ago and I have sweet spot for nested static ifs :)
Aug 04 2012