Thread overview
How to list aggregate members in order of declaration at compile time?
Nov 10, 2016
Ivan Kazmenko
Nov 11, 2016
Ivan Kazmenko
Nov 11, 2016
Jonathan M Davis
Nov 11, 2016
Ivan Kazmenko
Nov 11, 2016
Jonathan M Davis
Jun 28, 2018
Guillaume Lathoud
November 10, 2016
Hi.

I want to somehow list members of a class in the order of their declaration.  The immediate goal is to generate a few functions, like the "default" constructor for structs but only with all the fields, or the "reader" function, but I'm interested in the general question as well.

I can go the hard way and wrap every declaration into something that will collect them and then list in the right order.  The problem is, the declarations won't look normal then.

The documentation for __traits (allMembers, ...), __traits (derivedMembers, ...) and the like [1] explicitly says that the order is not defined.  Still, I've looked at Atila Neves' Cerealed serializer library, and it does use them [2].  Does it mean the order is unlikely to change at this point?

The documentation for std.traits' RepresentationTypeTuple [3] says things are listed in topological order, which formally does not restrict the order for flat structures again.  And the underlying implementation [4] of Fields uses .tupleof class property which, in turn, does not list any guarantees on the order [5].

So I'm confused.  What is considered the right way to list members when I care about their linear order?

Ivan Kazmenko.

[1] https://dlang.org/spec/traits.html#derivedMembers
[2] https://github.com/atilaneves/cerealed/blob/master/src/cerealed/cereal.d#L467
[3] https://dlang.org/phobos/std_traits.html#RepresentationTypeTuple
[4] https://github.com/dlang/phobos/blob/10cd84a/std/traits.d#L2279
[5] https://dlang.org/spec/class.html#class_properties

November 11, 2016
On Thursday, 10 November 2016 at 10:16:44 UTC, Ivan Kazmenko wrote:
> I want to somehow list members of a class in the order of their declaration.

Bump.  Anyone?  I've met my immediate goal by other means, but the general question remains.

If classes are no-go, basically, any aggregate will do if the order of declarations is reliably and reproducibly known at compile time.

I'm not much into compile-time reflection, yet, but I thought that's a basic operation.  Otherwise, how do people, for example, approach serializing arbitrary containers reproducibly across compiler versions - or they just don't?  Well, I've seen one example (Cerealed), but the implementation details there seem to contradict the current language documentation.

Ivan Kazmenko.

November 11, 2016
On Friday, November 11, 2016 21:26:10 Ivan Kazmenko via Digitalmars-d-learn wrote:
> On Thursday, 10 November 2016 at 10:16:44 UTC, Ivan Kazmenko
>
> wrote:
> > I want to somehow list members of a class in the order of their declaration.
>
> Bump.  Anyone?  I've met my immediate goal by other means, but the general question remains.
>
> If classes are no-go, basically, any aggregate will do if the order of declarations is reliably and reproducibly known at compile time.
>
> I'm not much into compile-time reflection, yet, but I thought that's a basic operation.  Otherwise, how do people, for example, approach serializing arbitrary containers reproducibly across compiler versions - or they just don't?  Well, I've seen one example (Cerealed), but the implementation details there seem to contradict the current language documentation.

I think that the simple truth of the matter is that nothing in the spec guarantees an order for any of the operations that give a list of members of a struct or class. It's just that the implementation doesn't typically change in a way that would change the order, and folks rely on the current implementation, and it works.

The correct way to get the list of member variables of a struct or class is the tupleof property. And the only order that really makes sense for it is the order of declaration. Because of what it is and what it would be used for with a struct, I think that it would be hard to argue that it would make any sense for it do anything else. For classes, it's more debatable given that the member variables rearranged within the object, but since tupleof only gives you the direct member variables and therefore doesn't give you the actual layout of the full class anyway, there really isn't any point in it giving anything but the declaration order. So, it wouldn't surprise me if Walter would agree to making it so that the spec guarantees that tupleof gives the member variables in the order that they were declared, but I would not expect such a guarantee from something like __traits(allMembers, T) which gives stuff like base class members as well as stuff like functions, where the order of declaration doesn't matter at all, and there is no obvious order that members should be listed in when you take stuff like base classes and interfaces into account.

I expect that it never occurred to Walter to specify that the order of the members mattered with tupleof and that that's why the spec doesn't say.

So, use tupleof, and you can create an enhancement request in bugzilla for the spec to be made clearer about it: https://issues.dlang.org

- Jonathan M Davis

November 11, 2016
On Friday, 11 November 2016 at 22:04:37 UTC, Jonathan M Davis wrote:
> ...
>
> I expect that it never occurred to Walter to specify that the order of the members mattered with tupleof and that that's why the spec doesn't say.
>
> So, use tupleof, and you can create an enhancement request in bugzilla for the spec to be made clearer about it: https://issues.dlang.org

Thanks for the answer!  So you think the order guarantee is likely to be just granted for .tupleof if asked for.  I hope to get to creating a documentation issue/PR next week, to see more reaction.

Ivan Kazmenko.

November 11, 2016
On Friday, November 11, 2016 22:26:20 Ivan Kazmenko via Digitalmars-d-learn wrote:
> On Friday, 11 November 2016 at 22:04:37 UTC, Jonathan M Davis
>
> wrote:
> > ...
> >
> > I expect that it never occurred to Walter to specify that the order of the members mattered with tupleof and that that's why the spec doesn't say.
> >
> > So, use tupleof, and you can create an enhancement request in bugzilla for the spec to be made clearer about it: https://issues.dlang.org
>
> Thanks for the answer!  So you think the order guarantee is likely to be just granted for .tupleof if asked for.  I hope to get to creating a documentation issue/PR next week, to see more reaction.

I suspect so, but I don't know so. Certainly, it seems conceivable that something dealing with structs and their layout would need to know the order, and having tupleof have a guaranteed order would be the easiest (though you could always look at each offset property individually and figure it out). And if you really do need to be able to do something like generate a constructor for a class based on the order of its member declarations, then you need tupleof to give the order of declaration, because the offset property won't necessarily match the order of declaration for a class.

So, just provide a solid use case (if not multiple) as to why it needs to have a specific order, and you probably stand a good chance of it being added to the spec - especially since it's what the implementation does anyway, and the implementation isn't likely to change. And given that tupleof simply gives the member variables, I don't know of a good argument for why it should ever do anything other than given them in the order that they're declared.

- Jonathan M Davis

June 28, 2018
On Friday, 11 November 2016 at 23:55:58 UTC, Jonathan M Davis wrote:
> ...
>
> So, just provide a solid use case (if not multiple) as to why it needs to have a specific order, and you probably stand a good chance of it being added to the spec - especially since it's what the implementation does anyway, and the implementation isn't likely to change. And given that tupleof simply gives the member variables, I don't know of a good argument for why it should ever do anything other than given them in the order that they're declared.
>
> - Jonathan M Davis

Hello, here is an issue (with a use case):
https://issues.dlang.org/show_bug.cgi?id=19036

Guillaume Lathoud