Thread overview
Using std traits
Jan 25, 2018
JN
Jan 25, 2018
Ali Çehreli
Jan 25, 2018
JN
January 25, 2018
I decided it's time to learn how std traits work. I still find the whole compile time business a bit weird to deal with, so I decided to write a simple JSON serializer for struct that loops over member fields and outputs them.

import std.stdio;
import std.json;
import std.traits;

struct TestStruct
{
	@("noserialize") int x;
	int y;
	int z;
}

void serialize(T)(T obj)
{
	if (is(T == struct))
	{
		foreach (i, member; FieldNameTuple!T)
		{
			if (!hasUDA!(member, "noserialize"))
			{
				writeln(member);
			}
		}
	} else {
		assert(0, "Not a struct");
	}
}

void main()
{
	TestStruct ts;
	ts.x = 1;
	ts.y = 2;
	ts.z = 3;
	serialize(ts);
}

here's a runnable version: https://ideone.com/U4ROAT


I expected it to output "y" "z", but "x" is also present. What am I doing wrong with hasUDA?
January 25, 2018
On 01/25/2018 11:49 AM, JN wrote:

>          foreach (i, member; FieldNameTuple!T)
>          {
>              if (!hasUDA!(member, "noserialize"))
>              {
>                  writeln(member);
>              }

'member' is a string local variable, which does not have that UDA. You need to get the symbol of the struct:

            if (!hasUDA!(__traits(getMember, T, member), "noserialize"))
            {
                writeln(member);
            }

However, note that you're using a compile-time foreach, which expands its body for each iteration. Since you used a regular if, you have three checks at runtime.

What you really want is use a 'static if':

            static if (!hasUDA!(__traits(getMember, T, member), "noserialize"))
            {
                writeln(member);
            }

Aaah... Much lighter... :)

Even further, you may want to consider using a 'static foreach':

        static foreach (i, member; FieldNameTuple!T)
        {
            // ...
        }

That is more powerful because it can iterate over more ranges. However there are some differences from the regular foreach: For example, 'static foreach' does not introduce a scope per iteration.

Ali
January 25, 2018
On Thursday, 25 January 2018 at 19:49:05 UTC, JN wrote:
> if (!hasUDA!(member, "noserialize"))

Nevermind, I get it now, member is only the field name, not a 'reference', changed it to:

if (!hasUDA!(mixin(T.stringof ~ "." ~ member), "noserialize"))

and works now