www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Define an order for allMembers traits

reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
D doc for for `__traits(allMembers, ...)` 
[says](https://dlang.org/spec/traits.html#allMembers) that "the 
order in which the strings appear in the result is not defined". 
Is it possible to define an order at least for some cases (I'm 
looking for structs actually)?

I think having guaranteed order for simple cases in beneficial:
```d
struct S
{
   int a,b;
   string c,d;
}

assert([ __traits(allMembers, S) ] == [ "a","b","c","d" ]);
```

This will especially help in my use case where I need to know the 
order in which struct members are declared. Right now I'm using 
UDA with index to explicitly set an order:
```d
struct S
{
    UDA(1) int a;
    UDA(2) int b;
    UDA(3) string c;
    UDA(4) string d;
}
```

Possible solution would be to use `__LINE__` but it won't work in 
this case:
```d
struct S
{
    UDA int a;  UDA int b;
}
```

The only solution that might work is to use 
`__traits(getLocation, ...)` which complicates introspection a 
lot: instead of simple usage of `__traits(allMembers, ...)` I'll 
have to sort all members by location and only then iterate over 
them.
Aug 23 2023
next sibling parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Wednesday, 23 August 2023 at 12:32:58 UTC, Andrey Zherikov 
wrote:
 Is it possible to define an order at least for some cases (I'm 
 looking for structs actually)?
What do you do with the order of declaration?
Aug 23 2023
parent reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Wednesday, 23 August 2023 at 12:39:09 UTC, Adam D Ruppe wrote:
 On Wednesday, 23 August 2023 at 12:32:58 UTC, Andrey Zherikov 
 wrote:
 Is it possible to define an order at least for some cases (I'm 
 looking for structs actually)?
What do you do with the order of declaration?
I'm developing a [library to parse command line arguments](https://github.com/andrey-zherikov/argparse). One type of arguments is positional argument which means that they have a position in command line. As of now (because the order of `allMembers` is not defined), these arguments are attributed the following way by explicitly providing the order: ```d struct Params { PositionalArgument(0) string firstName; PositionalArgument(1) string middleName; PositionalArgument(2) string lastName; } ``` If `allMembers` guarantees the order to be the same as the members are declared then the code above can be simplified to this: ```d struct Params { PositionalArgument string firstName, middleName, lastName; } ```
Aug 23 2023
next sibling parent reply Stefan Koch <uplink.coder googlemail.com> writes:
On Wednesday, 23 August 2023 at 13:53:30 UTC, Andrey Zherikov 
wrote:
 On Wednesday, 23 August 2023 at 12:39:09 UTC, Adam D Ruppe 
 wrote:
 On Wednesday, 23 August 2023 at 12:32:58 UTC, Andrey Zherikov 
 wrote:
 Is it possible to define an order at least for some cases 
 (I'm looking for structs actually)?
What do you do with the order of declaration?
I'm developing a [library to parse command line arguments](https://github.com/andrey-zherikov/argparse). One type of arguments is positional argument which means that they have a position in command line. As of now (because the order of `allMembers` is not defined), these arguments are attributed the following way by explicitly providing the order: ```d struct Params { PositionalArgument(0) string firstName; PositionalArgument(1) string middleName; PositionalArgument(2) string lastName; } ``` If `allMembers` guarantees the order to be the same as the members are declared then the code above can be simplified to this: ```d struct Params { PositionalArgument string firstName, middleName, lastName; } ```
My 10 cents on this are: In the general case we cannot guarantee the order of __traits(allMembers) as they might be generated by meta-programming which does not have an obvious execution order. So the question is we guarantee lexical order in the cases where no meta programming is used to introduce members? I think we can do that.
Aug 23 2023
parent Alexandru Ermicioi <alexandru.ermicioi gmail.com> writes:
On Wednesday, 23 August 2023 at 14:24:46 UTC, Stefan Koch wrote:
 ...
 So the question is we guarantee lexical order in the cases 
 where no meta programming is used to introduce members?
 I think we can do that.
No lexical, please. It would be worse, than order in which elements are declared. At least with the later, you could also use it for some meaningful order, such as first declared takes priority for some action, or etc. Having it all sorted lexical would hinder it. Besides, lexical ordering can also be done already at compile time.
Aug 23 2023
prev sibling next sibling parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Wednesday, 23 August 2023 at 13:53:30 UTC, Andrey Zherikov 
wrote:
 ```d
 struct Params
 {
      PositionalArgument(0)
     string firstName;

      PositionalArgument(1)
     string middleName;

      PositionalArgument(2)
     string lastName;
 }
 ```
tbh I actually prefer this code to the alternative
 If `allMembers` guarantees the order to be the same as the 
 members are declared then the code above can be simplified to 
 this:
but yeah, what others say about the tuple thing is prolly the best thing by spec tho in practice allMembers is in order but relying on that might lead to troube some random day
Aug 23 2023
parent Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Wednesday, 23 August 2023 at 16:52:36 UTC, Adam D Ruppe wrote:
 but yeah, what others say about the tuple thing is prolly the 
 best thing by spec
I don't see that the order of tupleof is specified for structs there.
Aug 23 2023
prev sibling parent reply John Colvin <john.loughran.colvin gmail.com> writes:
On Wednesday, 23 August 2023 at 13:53:30 UTC, Andrey Zherikov 
wrote:
 On Wednesday, 23 August 2023 at 12:39:09 UTC, Adam D Ruppe 
 wrote:
 On Wednesday, 23 August 2023 at 12:32:58 UTC, Andrey Zherikov 
 wrote:
 Is it possible to define an order at least for some cases 
 (I'm looking for structs actually)?
What do you do with the order of declaration?
I'm developing a [library to parse command line arguments](https://github.com/andrey-zherikov/argparse). One type of arguments is positional argument which means that they have a position in command line. As of now (because the order of `allMembers` is not defined), these arguments are attributed the following way by explicitly providing the order: ```d struct Params { PositionalArgument(0) string firstName; PositionalArgument(1) string middleName; PositionalArgument(2) string lastName; } ``` If `allMembers` guarantees the order to be the same as the members are declared then the code above can be simplified to this: ```d struct Params { PositionalArgument string firstName, middleName, lastName; } ```
Just sort allMembers by .offsetof? You might need a small amount of compile time gymnastics but it’s doable.
Aug 23 2023
parent Adam D Ruppe <destructionator gmail.com> writes:
On Thursday, 24 August 2023 at 00:11:07 UTC, John Colvin wrote:
 Just sort allMembers by .offsetof? You might need a small 
 amount of compile time gymnastics but it’s doable.
Adds quite a bit of potential complication - what if two things have the same offset of? What if they don't have one? Doing this without care can bloat compile times too... but yeah, it was my first thought too tbh, with the appropriate filters you can make that work.
Aug 23 2023
prev sibling next sibling parent "Richard (Rikki) Andrew Cattermole" <richard cattermole.co.nz> writes:
Another way to do this (which should be defined):

```d
void main() {
     S s;

     static foreach(f; s.tupleof) {
         pragma(msg, __traits(identifier, f));
     }
}

struct S {
    int a, b;

     union {
         string c, d;
     }
}
```
Aug 23 2023
prev sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Wednesday, 23 August 2023 at 12:32:58 UTC, Andrey Zherikov 
wrote:
 This will especially help in my use case where I need to know 
 the order in which struct members are declared. Right now I'm 
 using UDA with index to explicitly set an order:
 ```d
 struct S
 {
    UDA(1) int a;
    UDA(2) int b;
    UDA(3) string c;
    UDA(4) string d;
 }
 ```
For this use case, you should use `.tupleof` instead of `__traits(allMembers)`, which [is guaranteed by the spec to give the fields in declaration order][1]. [1]: https://dlang.org/spec/class.html#class_properties
Aug 23 2023
parent reply Andrey Zherikov <andrey.zherikov gmail.com> writes:
On Wednesday, 23 August 2023 at 15:32:02 UTC, Paul Backus wrote:
 For this use case, you should use `.tupleof` instead of 
 `__traits(allMembers)`, which [is guaranteed by the spec to 
 give the fields in declaration order][1].

 [1]: https://dlang.org/spec/class.html#class_properties
This link says "The order of the fields in the tuple matches the order in which the fields are declared" for the classes. I don't see such statement for structs [here](https://dlang.org/spec/struct.html#struct_instance_properties).
Aug 23 2023
next sibling parent Paul Backus <snarwin gmail.com> writes:
On Wednesday, 23 August 2023 at 16:28:27 UTC, Andrey Zherikov 
wrote:
 On Wednesday, 23 August 2023 at 15:32:02 UTC, Paul Backus wrote:
 For this use case, you should use `.tupleof` instead of 
 `__traits(allMembers)`, which [is guaranteed by the spec to 
 give the fields in declaration order][1].

 [1]: https://dlang.org/spec/class.html#class_properties
This link says "The order of the fields in the tuple matches the order in which the fields are declared" for the classes. I don't see such statement for structs [here](https://dlang.org/spec/struct.html#struct_instance_properties).
The spec isn't totally clear, but I believe the intent is to say that it works the same way for structs unless otherwise stated. Certainly, in practice, the fields are always in declaration order.
Aug 23 2023
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 8/23/23 18:28, Andrey Zherikov wrote:
 On Wednesday, 23 August 2023 at 15:32:02 UTC, Paul Backus wrote:
 For this use case, you should use `.tupleof` instead of 
 `__traits(allMembers)`, which [is guaranteed by the spec to give the 
 fields in declaration order][1].

 [1]: https://dlang.org/spec/class.html#class_properties
This link says "The order of the fields in the tuple matches the order in which the fields are declared" for the classes. I don't see such statement for structs [here](https://dlang.org/spec/struct.html#struct_instance_properties).
Well, it refers to the class version and I think it is clear that it must be ordered. Anyway, if you don't trust this for some reason, you can always just sort by "offsetof". (Provided you don't want to use empty static arrays.)
Aug 23 2023
parent Walter Bright <newshound2 digitalmars.com> writes:
On 8/23/2023 2:17 PM, Timon Gehr wrote:
 Well, it refers to the class version and I think it is clear that it must be 
 ordered.
Yes. It is written the way it is because I was writing a lot of text in the spec and didn't want to repeat things. Another problem with repetition is the texts will inevitably diverge, and then the poor reader wonders why they are different.
Aug 23 2023