Thread overview
How to get only the field name from an alias?
Feb 21, 2023
Elfstone
Feb 21, 2023
ryuukk_
Feb 21, 2023
Elfstone
Feb 21, 2023
Adam D Ruppe
Feb 22, 2023
Elfstone
February 21, 2023

I'm experimenting on a serializer design. The idea includes a shorthand for processing a field and its attributes with an alias. But I'm not sure whether I can gather enough information from it, such as the name of the field. apparently F.stringof stands for "this.<fieldname>" in this context. So how can I get only the field's name? And is it possible to check if F is a field? -- In a well defined manner.

import std.stdio;

void processField(alias F)(Serializer sz) // is field?
{
	writeln("attrs ", __traits(getAttributes, F)); // OK
	writeln(F.stringof); // "this.intField"
	sz.process(F.stringof, F); // "serializing int this.intField: 0"
}

class Serializer
{

	void process(string k, ref int v)
	{
		writeln("serializing int ", k, ": ", v);
	}

	void process(string k, ref long v)
	{
		writeln("serializing long ", k, ": ", v);
	}

	void process(U)(ref U v) if (is(U == struct))
	{
		v.serialize(this);
	}
}

struct OldName
{
	string name;
}

struct Serializable
{
	@OldName("ifield")
	int intField;

	void serialize(Serializer sz)
	{
		sz.processField!intField();
	}
}

void main()
{
	import std.stdio;
	import std.traits;
	import core.internal.traits;

	Serializable v;
	auto sz = new Serializer();
	sz.process(v);
}
February 21, 2023

I'm not sure what the solution is for your specific question, but there is some alternative way you could do: (no longer need function on your struct)

I tried to comment the lines, even thought i'm not sure i remember everything correctly, but it compiles :p

More info: https://dlang.org/spec/traits.html

import std.stdio;

class Serializer
{
    void process(string k, ref int v)
    {
        writeln("serializing int ", k, ": ", v);
    }

    void process(string k, ref long v)
    {
        writeln("serializing long ", k, ": ", v);
    }

    void process(U)(ref U v) if (is(U == struct))
    {
        // get all members from U
        static foreach (member; __traits(allMembers, U))
        {
            // get attributes from U.member
            static foreach (attr; __traits(getAttributes, __traits(getMember, U, member)))
            {
                // is the attribute OldName
                static if (is(typeof(attr) == OldName))
                {
                    // the name you put in OldName attribute
                    string oldName = attr.name;
                    auto value = __traits(getMember, v, member);

                    writeln("field: ", member);
                    writeln("oldname: ", oldName);
                    writeln("value: ", value);
                }
            }
        }
    }
}

struct OldName
{
    string name;
}

struct Serializable
{
    @OldName("ifield")
    int intField;
}

void main()
{
    import std.stdio;
    import std.traits;
    import core.internal.traits;

    Serializable v;
    auto sz = new Serializer();
    sz.process(v);
}
February 21, 2023

On Tuesday, 21 February 2023 at 03:13:38 UTC, ryuukk_ wrote:

>

I'm not sure what the solution is for your specific question, but there is some alternative way you could do: (no longer need function on your struct)

[...]

This is super neat, but the order of the fields will have to be frozen, and I won't be able to do something like this:

sz.processField!hasData();
if (this.hasData)
{
    sz.processField!data();
}

Unless I can mark versions and dependencies with attributes and analyse them somehow.

The Deserializer shares the same interface by the way.

February 21, 2023
On Tuesday, 21 February 2023 at 02:41:34 UTC, Elfstone wrote:
> apparently F.stringof

You almost never want to use .stringof, instead try __traits(identifier, F) and see what it gives you.


Alternatively, loop over __traits(allMembers) which gives you the member names and pass that down. You can pull all the info out of allMembers with getMember and then other things to filter it out.
February 22, 2023
On Tuesday, 21 February 2023 at 12:32:51 UTC, Adam D Ruppe wrote:
> On Tuesday, 21 February 2023 at 02:41:34 UTC, Elfstone wrote:
>> apparently F.stringof
>
> You almost never want to use .stringof, instead try __traits(identifier, F) and see what it gives you.
>
>
> Alternatively, loop over __traits(allMembers) which gives you the member names and pass that down. You can pull all the info out of allMembers with getMember and then other things to filter it out.

Thanks, Adam! Didn't know such a trait existed and that it could work for aliases.