digitalmars.D.learn - Curious effect with traits, meta, and a foreach loop ... mystifies me.
- james.p.leblanc (43/43) Sep 07 2021 Dear All,
- Adam D Ruppe (28/33) Sep 07 2021 tuples only exist at compile time, so you'd have to make sure the
- james.p.leblanc (22/33) Sep 07 2021 Adam,
- Adam D Ruppe (17/22) Sep 08 2021 You might be able to just cast the struct to a static array of
- Tejas (20/58) Sep 08 2021 from what I understand you want to change the aligned data that
- Tejas (3/24) Sep 08 2021 Also, link :
- james.p.leblanc (12/26) Sep 09 2021 Adam, Tejas,
- Bastiaan Veelo (16/32) Sep 08 2021 As Adam mentioned `tupleof` only exists at compile time, and a
Dear All, In playing with some reflection and meta programming, this curiosity appeared. Does someone understand what is happening? I would appreciate learning about it if possible. Enclosed code snippet tells the story: ```d import std.stdio; import std.traits; import std.meta; struct S0{ double[3] x; }; struct S1{ double junk0 ; double[3] x; }; union U { S0 s0; S1 s1; } void main(){ U u; double* ptr; u.s0.x = [ 0.0, 0.1, 0.3 ]; u.s1.x = [ 1.0, 1.1, 1.3 ]; writeln("typeid( u.tupleof): ", typeid( u.tupleof ) ); writeln("typeid( u.tupleof[0]): ", typeid( u.tupleof[0] ) ); writeln("typeid( u.tupleof[0].x): ", typeid( u.tupleof[0].x ) ); writeln(); // indeed both tuples exist writeln("u.tupleof[0].x.ptr: ", u.tupleof[0].x.ptr ); writeln("u.tupleof[1].x.ptr: ", u.tupleof[1].x.ptr ); // this is fine (notice that 'val' is never used foreach( i, val ; u.tupleof ){ ptr = u.tupleof[i].x.ptr; writeln("ptr: ", ptr); } // this fails with: "Error: variable 'i' cannot be read at compile time // // foreach( i ; 0 .. 3 ){ // ptr = u.tupleof[i].x.ptr; // writeln("ptr: ", ptr); // } } ``` Best Regards, James
Sep 07 2021
On Tuesday, 7 September 2021 at 17:24:34 UTC, james.p.leblanc wrote:// this fails with: "Error: variable 'i' cannot be read at compile time // // foreach( i ; 0 .. 3 ){ // ptr = u.tupleof[i].x.ptr;tuples only exist at compile time, so you'd have to make sure the indexing is itself compile time. Consider that unlike an array, each index might give a different type, so like what would struct A { int a; string b; } A a; int idx; some_type c = a.tupleof[idx]; Which type is some_type? Is it int or string? Impossible to tell since it doesn't know what idx is. So idx needs to be known at compile time so it knows which type you get there. The reason why it works here: foreach( i, val ; u.tupleof ){ is because the compiler knows you're specifically looping over the tupleof, so it expands it and knows what i is going to be at compile time. If you assigned that i to an intermediate variable then it would break this direct knowledge and it doesn't compile again. If you want to do a runtime lookup, you need to separate the two pieces. This pattern works: switch(runtime_index) { foreach(i, val; item.tupleof) case i: // use val } So the switch is at runtime but the loop and cases are all known at compile time.
Sep 07 2021
On Tuesday, 7 September 2021 at 17:33:31 UTC, Adam D Ruppe wrote:On Tuesday, 7 September 2021 at 17:24:34 UTC, james.p.leblanc wrote: If you want to do a runtime lookup, you need to separate the two pieces. This pattern works: switch(runtime_index) { foreach(i, val; item.tupleof) case i: // use val } So the switch is at runtime but the loop and cases are all known at compile time.Adam, Thanks for the very fast, and very thorough explanation. I especially appreciate the fact that you seem to have predicted where my thoughts were heading with my experiments ... The "switch(runtime_index)" snippet will come in handy ... What I would **REALLY** like is to be able to do (but I think this is impossible) would be to "dig out" the needed "x" array depending on which one of them suits my alignment needs. (Yes, I am still playing with avx2 ideas ...). What I mean by "dig out" the needed "x" is: if I could alias/enum/ or someother trick be then able just to use that "x" as a simple static array. (I doubt this is possible ... but .... ?). Thanks again, Keep Warm in Upstate! James
Sep 07 2021
On Tuesday, 7 September 2021 at 17:47:15 UTC, james.p.leblanc wrote:What I mean by "dig out" the needed "x" is: if I could alias/enum/ or someother trick be then able just to use that "x" as a simple static array.You might be able to just cast the struct to a static array of the same size if the types are all compatible. Like a reinterpret cast of the raw memory kind of idea. struct A { int a; int b; } void main() { A a; int[2] as_array = cast(int[2]) a; } That works. But idk if it will help with your alignment issue, I don't know much about avx at all.Thanks again, Keep Warm in Upstate!It has actually been kinda nice the last few days! Winter coming soon though, sigh.
Sep 08 2021
On Tuesday, 7 September 2021 at 17:47:15 UTC, james.p.leblanc wrote:On Tuesday, 7 September 2021 at 17:33:31 UTC, Adam D Ruppe wrote:from what I understand you want to change the aligned data that you're referring to at runtime. ```d void main() { import std.experimental.allocator.mallocator; import std.stdio: write, writeln, writef, writefln, readf; uint alignment, length; readf!"%u %u"(length,alignment); auto buffer = AlignedMallocator.instance.alignedAllocate(length, alignment); writeln(&buffer[0]); scope(exit) AlignedMallocator.instance.deallocate(buffer); //... } ``` Is this it?On Tuesday, 7 September 2021 at 17:24:34 UTC, james.p.leblanc wrote: If you want to do a runtime lookup, you need to separate the two pieces. This pattern works: switch(runtime_index) { foreach(i, val; item.tupleof) case i: // use val } So the switch is at runtime but the loop and cases are all known at compile time.Adam, Thanks for the very fast, and very thorough explanation. I especially appreciate the fact that you seem to have predicted where my thoughts were heading with my experiments ... The "switch(runtime_index)" snippet will come in handy ... What I would **REALLY** like is to be able to do (but I think this is impossible) would be to "dig out" the needed "x" array depending on which one of them suits my alignment needs. (Yes, I am still playing with avx2 ideas ...). What I mean by "dig out" the needed "x" is: if I could alias/enum/ or someother trick be then able just to use that "x" as a simple static array. (I doubt this is possible ... but .... ?). Thanks again, Keep Warm in Upstate! James
Sep 08 2021
On Thursday, 9 September 2021 at 05:32:29 UTC, Tejas wrote:On Tuesday, 7 September 2021 at 17:47:15 UTC, james.p.leblanc wrote:Also, link : https://dlang.org/phobos/std_experimental_allocator_mallocator.html#.Mallocator.reallocate[...]from what I understand you want to change the aligned data that you're referring to at runtime. ```d void main() { import std.experimental.allocator.mallocator; import std.stdio: write, writeln, writef, writefln, readf; uint alignment, length; readf!"%u %u"(length,alignment); auto buffer = AlignedMallocator.instance.alignedAllocate(length, alignment); writeln(&buffer[0]); scope(exit) AlignedMallocator.instance.deallocate(buffer); //... } ``` Is this it?
Sep 08 2021
On Thursday, 9 September 2021 at 05:37:35 UTC, Tejas wrote:On Thursday, 9 September 2021 at 05:32:29 UTC, Tejas wrote:writeln(&buffer[0]);On Tuesday, 7 September 2021 at 17:47:15 UTC, james.p.leblanc wrote:[...]Adam, Tejas, Thanks for all of your kind suggestions (the struct wrapper -as_array, runtime switch), and (AlignedMallocator). All of these move me closer to a solution. Moreover, the suggestions give me a broader perspective. So I very much appreciate the time and effort volunteered by the dlang community to help newcomers such as myself. Best Regards, Jamesscope(exit) AlignedMallocator.instance.deallocate(buffer); //... } ``` Is this it?Also, link : https://dlang.org/phobos/std_experimental_allocator_mallocator.html#.Mallocator.reallocate
Sep 09 2021
On Tuesday, 7 September 2021 at 17:24:34 UTC, james.p.leblanc wrote:```d /*…*/ // this is fine (notice that 'val' is never used foreach( i, val ; u.tupleof ){ ptr = u.tupleof[i].x.ptr; writeln("ptr: ", ptr); } // this fails with: "Error: variable 'i' cannot be read at compile time // // foreach( i ; 0 .. 3 ){ // ptr = u.tupleof[i].x.ptr; // writeln("ptr: ", ptr); // } } ```As Adam mentioned `tupleof` only exists at compile time, and a `foreach` over a `tupleof` gets unrolled at compile time, akin to a `static foreach`. Consequently you can make your snippet work by prepending `static` (and fixing the range): ```d static foreach (i; 0 .. u.tupleof.length) { ptr = u.tupleof[i].x.ptr; writeln("ptr: ", ptr); } ``` https://run.dlang.io/is/T6jrjf Not sure if that helps in what you’re trying to achieve though, as that isn’t clear to me. —Bastiaan.
Sep 08 2021