Thread overview
template returning delegate
Aug 21, 2013
Marek Janukowicz
Re: A template returning a delegate [was: template returning delegate]
Aug 21, 2013
Marek Janukowicz
Aug 22, 2013
Marek Janukowicz
August 21, 2013
Yet another problem I just spotted:

-----------------------

import std.stdio, std.string;

struct Val {
  int i;
  byte b;
}

template templ( T ) {

   auto templ (T obj, string name) {
    foreach( s; __traits(derivedMembers, T)) {
      if (s == name) {
        static if( is(typeof(__traits(getAttributes, __traits(getMember, T,
s))) blah)) { // Rule out "non-regular" members
          //return format( "%s", __traits(getMember, obj, s)); // Version A
          return cast(string delegate())() { return
format("%s",__traits(getMember, obj, s)); }; // Version B
        }
      }
    }
    throw new Exception("Invalid member");
  }
}

void main (string [] args) {
  Val v = Val(1, 2);
  //writefln( "%s: %s", args[1], templ!()(v, args[1]));   // Version A
  writefln( "%s: %s", args[1], templ!()(v, args[1])()); // Version B
}

---------------------------

Now running:
$ dmd -run member.d i
/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.3/../../../../x86_64-pc-linux-
gnu/bin/ld: Warning: size of symbol
`_D6member23__T5templTS6member3ValZ5templFNfS6member3ValAyaZDFZAya9__lambda1MFZAya'
changed from 32 in member.o to 33 in member.o
i: 1

$ dmd -run member.d b
/usr/lib/gcc/x86_64-pc-linux-gnu/4.6.3/../../../../x86_64-pc-linux-
gnu/bin/ld: Warning: size of symbol
`_D6member23__T5templTS6member3ValZ5templFNfS6member3ValAyaZDFZAya9__lambda1MFZAya'
changed from 32 in member.o to 33 in member.o
b: 1  # Why not 2?

If I compile using ldc2 I get exactly the same result, so the delegate returned from template always returns value of "i" member (maybe it's always the first member that is returned). Ld warning is not present then.

However if I comment "Version B" lines and uncomment "Version A" (which means I return the result directly instead of returning the delegate I get expected results:

$ dmd -run member.d i
i: 1

$ dmd -run member.d b
b: 2

Also no ld warning in this case.

-- 
Marek Janukowicz
August 21, 2013
After I sent the message I realized my limited English knowledge made me make a subject that actually had quite a different meaning than I intended :)

Now it's hopefully fine or at least less ambiguous.

-- 
Marek Janukowicz
August 22, 2013
Marek Janukowicz wrote:

> Yet another problem I just spotted:
> 
> -----------------------
> 
> import std.stdio, std.string;
> 
> struct Val {
>   int i;
>   byte b;
> }
> 
> template templ( T ) {
> 
>    auto templ (T obj, string name) {
>     foreach( s; __traits(derivedMembers, T)) {
>       if (s == name) {
>         static if( is(typeof(__traits(getAttributes, __traits(getMember,
>         T,
> s))) blah)) { // Rule out "non-regular" members
>           //return format( "%s", __traits(getMember, obj, s)); // Version
>           A return cast(string delegate())() { return
> format("%s",__traits(getMember, obj, s)); }; // Version B
>         }
>       }
>     }
>     throw new Exception("Invalid member");
>   }
> }
> 
> void main (string [] args) {
>   Val v = Val(1, 2);
>   //writefln( "%s: %s", args[1], templ!()(v, args[1]));   // Version A
>   writefln( "%s: %s", args[1], templ!()(v, args[1])()); // Version B
> }
> 
> ---------------------------
> 
> Now running:
> $ dmd -run member.d i
> /usr/lib/gcc/x86_64-pc-linux-gnu/4.6.3/../../../../x86_64-pc-linux-
> gnu/bin/ld: Warning: size of symbol
> 
`_D6member23__T5templTS6member3ValZ5templFNfS6member3ValAyaZDFZAya9__lambda1MFZAya'
> changed from 32 in member.o to 33 in member.o
> i: 1
> 
> $ dmd -run member.d b /usr/lib/gcc/x86_64-pc-linux-gnu/4.6.3/../../../../x86_64-pc-linux- gnu/bin/ld: Warning: size of symbol
> 
`_D6member23__T5templTS6member3ValZ5templFNfS6member3ValAyaZDFZAya9__lambda1MFZAya'
> changed from 32 in member.o to 33 in member.o
> b: 1  # Why not 2?
> 
> If I compile using ldc2 I get exactly the same result, so the delegate returned from template always returns value of "i" member (maybe it's always the first member that is returned). Ld warning is not present then.
> 
> However if I comment "Version B" lines and uncomment "Version A" (which means I return the result directly instead of returning the delegate I get expected results:
> 
> $ dmd -run member.d i
> i: 1
> 
> $ dmd -run member.d b
> b: 2
> 
> Also no ld warning in this case.

Figured it out - this code works as expected:
import std.stdio, std.string;

struct Val {
  int i;
  byte b;
}

template templ( T ) {

  auto dg(alias s)( T obj ) {
    return () { return format("%s",__traits(getMember, obj, s)); };
  }

   auto templ (T obj, string name) {
    foreach( s; __traits(derivedMembers, T)) {
      if (s == name) {
        static if( is(typeof(__traits(getAttributes, __traits(getMember, T,
s))) blah)) { // Rule out "non-regular" members
          return dg!(s)(obj);
        }
      }
    }
    throw new Exception("Invalid member");
  }
}

void main (string [] args) {
  Val v = Val(1, 2);
  writefln( "%s: %s", args[1], templ!()(v, args[1])());
}

My mistake was to return delegate with __traits directly inside, why the correct way to do this was to create delegate using template. However, now I'm a bit confused my code worked at all instead of failing right away.

-- 
Marek Janukowicz