Hello,
currently there is no official guarantee on the order returned by .tupleof:
https://dlang.org/spec/class.html#class_properties
I have a use case where I'd like to serialize most fields of a class, *in their declaration order*, into a byte array. The fields are either simple arithmetic types, or dynamic arrays of arithmetic types, so I am currently doing something like this:
class A {
int x,y,z;
int _internal_use_only;
int[] arr;
void packTo( ref ubyte[] result )
{
result.length = 0;
static foreach( i, field; A.tupleof ) // <<< HERE
{
static if (!__traits( identifier, field ).startsWith( "_" ))
{
{
ubyte[] b;
static if (__traits( isArithmetic, typeof( field ) ))
{
b ~= nativeToLittleEndian( field );
}
else
{
foreach( v; field )
b ~= nativeToLittleEndian( v );
}
result ~= b;
}
}
}
}
}
Since in my use case, the serialization order MUST match a spec, it is important to have a guarantee on the .tupleof order.
The current implementations already seem to guarantee that order. Would it be thinkable to have the guarantee in the spec as well?
Note: I found a previous discussion on this, but no issue:
https://forum.dlang.org/post/[email protected]
Thanks!
Guillaume Lathoud
Comment #1 by doob — 2018-06-28T10:20:41Z
As a workaround, if your specification contains the names you could lookup the names using in the class using __traits(identifier, A.tupleof[i]).
Comment #2 by timosesu — 2018-06-28T14:34:51Z
I also have code depending on this property of tupleof (ordered as declared) in a struct.
In my case the struct layout is handed to me and access to its properties/members has to be in the order the struct is layed out. If .tupleof were to change ever it would be a problem in this case.
Comment #3 by gsub — 2018-07-04T05:57:02Z
Thanks for the answers. In another use case there is a class hierarchy, I also need the fields of the base class, which .tupleof does not provide, so I am not sure anymore how useful the present issue would be. (I ended up using something along this line: [__traits( allMembers, MyClass)].sort() )
Maybe the spec could simply state that .tupleof does not provide any order guarantee, as already specified for __traits( allMembers, MyClass ) and __traits( derivedMembers, MyClass ).
Comment #4 by doob — 2018-07-04T10:38:20Z
(In reply to Guillaume Lathoud from comment #3)
> In another use case there is a class hierarchy, I
> also need the fields of the base class, which .tupleof does not provide, so
> I am not sure anymore how useful the present issue would be.
To get the fields of the base class you can upcast it and then use .tupleof. That is: (cast(Base) subclassObject).tupleof. You can also use some traits in Phobos to get the base class from a subclass.
Comment #5 by gsub — 2018-07-04T11:49:52Z
(In reply to Jacob Carlborg from comment #4)
> To get the fields of the base class you can upcast it and then use .tupleof.
> That is: (cast(Base) subclassObject).tupleof. You can also use some traits
> in Phobos to get the base class from a subclass.
Thanks!
Now I see that the official .tupleof example *does* rely on the proper order: https://dlang.org/spec/class.html#class_properties
foo.tupleof[0] = 1; // set foo.x to 1
foo.tupleof[1] = 2; // set foo.y to 2
...so I guess this guarantee should be made explicit. That would be the topic of the issue here.
One the side: is there an easy way to concatenate two expression sequences? I am thinking of something like BaseClass.tupleof ~ ChildClass.tupleof
Comment #6 by doob — 2018-07-04T18:59:25Z
(In reply to Guillaume Lathoud from comment #5)
> One the side: is there an easy way to concatenate two expression sequences?
> I am thinking of something like BaseClass.tupleof ~ ChildClass.tupleof
You can concatenate a tuple of types using std.typecons.AliasSeq. That would be used like this:
alias a = AliasSeq!(typeof(BaseClass.tupleof), typeof(ChildClass.tupleof));
It seems it's not possible to concatenate without using "typeof".
Comment #7 by gsub — 2018-07-05T04:39:38Z
(In reply to Jacob Carlborg from comment #6)
> You can concatenate a tuple of types using std.typecons.AliasSeq. That would
> be used like this:
>
> alias a = AliasSeq!(typeof(BaseClass.tupleof), typeof(ChildClass.tupleof));
>
> It seems it's not possible to concatenate without using "typeof".
Thanks!
Comment #8 by dlang-bot — 2022-07-20T11:20:52Z
@RazvanN7 created dlang/dlang.org pull request #3346 "Fix Issue 19036 - .tupleof order guarantee" fixing this issue:
- Fix Issue 19036 - .tupleof order guarantee
https://github.com/dlang/dlang.org/pull/3346
Comment #9 by dlang-bot — 2022-07-20T12:08:06Z
dlang/dlang.org pull request #3346 "Fix Issue 19036 - .tupleof order guarantee" was merged into master:
- 633d7fc97321acdd71a3c01cd385d8f4166e1dca by RazvanN7:
Fix Issue 19036 - .tupleof order guarantee
https://github.com/dlang/dlang.org/pull/3346