www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - How to obtain Variant underlying type?

reply anonymouse <anany mouse.com> writes:
std.variant;
Variant v = [[1], [2], [3]];

writeln(v.type); // int[][]
typeof(v.type); // TypeInfo
assert(v.type == typeid(int[][]);

As demonstrated by the assert statement, .type returns the typeid 
of the underlying type. How would I obtain the actual type such 
that:

      auto vb = v.base; // what should I put here to achieve the 
following:
      typeof(vb); // int[][]
      assert(vb == [[1], [2], [3]]);

--anonymouse
Jul 09 2022
parent reply Adam D Ruppe <destructionator gmail.com> writes:
On Saturday, 9 July 2022 at 14:36:44 UTC, anonymouse wrote:
      auto vb = v.base; // what should I put here to achieve the 
 following:
      typeof(vb); // int[][]
Impossible; Variant's type is only known at runtime, and this would require compile time knowledge.
Jul 09 2022
parent reply anonymouse <anany mouse.com> writes:
On Saturday, 9 July 2022 at 14:46:36 UTC, Adam D Ruppe wrote:
 Impossible; Variant's type is only known at runtime, and this 
 would require compile time knowledge.
Hmmm. Okay, thanks. What I really need to know is how many dimensions an array has and the total elements per dimension so that I can create temporary storage for it later. this(T)(T a) in(imported!"std.traits".isDynamic!T) { data = a; // data is of type Variant shape = [a.length, {?, ...}]; // what's the best way to deterine? } Thanks, --anonymouse
Jul 09 2022
parent reply jfondren <julian.fondren gmail.com> writes:
On Saturday, 9 July 2022 at 23:04:20 UTC, anonymouse wrote:
 On Saturday, 9 July 2022 at 14:46:36 UTC, Adam D Ruppe wrote:
 Impossible; Variant's type is only known at runtime, and this 
 would require compile time knowledge.
Hmmm. Okay, thanks. What I really need to know is how many dimensions an array has and the total elements per dimension so that I can create temporary storage for it later. this(T)(T a) in(imported!"std.traits".isDynamic!T) { data = a; // data is of type Variant shape = [a.length, {?, ...}]; // what's the best way to deterine? } Thanks, --anonymouse
```d import std.variant : Variant; size_t[] shape(Variant v) { import std.variant : VariantException; size_t[] s; try { while (true) { Variant elem = v[0]; s ~= v.length; v = elem; } } catch (VariantException e) { return s; } } unittest { assert([3, 1] == [[1], [2], [3]].Variant.shape); assert([2, 1] == [[1], [2]].Variant.shape); assert([2, 2] == [[1, 0], [2, 0]].Variant.shape); assert([2] == [1, 2].Variant.shape); assert([] == 2.Variant.shape); // irregularity not checked assert([2, 2] == [[1, 0], [2]].Variant.shape); // arguably should be [2, 0] assert([2] == [[], []].Variant.shape); } ```
Jul 09 2022
parent reply anonymouse <anany mouse.com> writes:
On Sunday, 10 July 2022 at 06:26:37 UTC, jfondren wrote:
 ```d
 import std.variant : Variant;

 size_t[] shape(Variant v) {
     import std.variant : VariantException;

     size_t[] s;
     try {
         while (true) {
             Variant elem = v[0];
             s ~= v.length;
             v = elem;
         }
     } catch (VariantException e) {
         return s;
     }
 }
 ```
Thank you very much.
Jul 10 2022
parent reply drug007 <drug2004 bk.ru> writes:
On 7/10/22 20:26, anonymouse wrote:
 On Sunday, 10 July 2022 at 06:26:37 UTC, jfondren wrote:
 ```d
 import std.variant : Variant;

 size_t[] shape(Variant v) {
     import std.variant : VariantException;

     size_t[] s;
     try {
         while (true) {
             Variant elem = v[0];
             s ~= v.length;
             v = elem;
         }
     } catch (VariantException e) {
         return s;
     }
 }
 ```
Thank you very much.
I'd like to say that using of exception to break loop is really bad. Exception is exceptional thing but in the case above the exception is ordinary completion of the loop happens on regular basis. Don't do that.
Jul 10 2022
next sibling parent reply Paul Backus <snarwin gmail.com> writes:
On Sunday, 10 July 2022 at 18:31:46 UTC, drug007 wrote:
 On 7/10/22 20:26, anonymouse wrote:
 On Sunday, 10 July 2022 at 06:26:37 UTC, jfondren wrote:
 ```d
 import std.variant : Variant;

 size_t[] shape(Variant v) {
     import std.variant : VariantException;

     size_t[] s;
     try {
         while (true) {
             Variant elem = v[0];
             s ~= v.length;
             v = elem;
         }
     } catch (VariantException e) {
         return s;
     }
 }
 ```
Thank you very much.
I'd like to say that using of exception to break loop is really bad. Exception is exceptional thing but in the case above the exception is ordinary completion of the loop happens on regular basis. Don't do that.
For reference, this is the more correct way: ```d while (cast(TypeInfo_Array) v.type !is null) { Variant elem = v[0]; // etc. } ``` Hard to blame anyone for not coming up with that on their first try, especially since `TypeInfo_Array` is not even documented--you have to read the source of `object.d` to find out about it.
Jul 10 2022
parent anonymouse <anany mouse.com> writes:
On Sunday, 10 July 2022 at 19:14:34 UTC, Paul Backus wrote:
 For reference, this is the more correct way:

 ```d
 while (cast(TypeInfo_Array) v.type !is null) {
     Variant elem = v[0];
     // etc.
 }
 ```

 Hard to blame anyone for not coming up with that on their first 
 try, especially since `TypeInfo_Array` is not even 
 documented--you have to read the source of `object.d` to find 
 out about it.
I honestly cannot say why but I was having a problem using this earlier. After several hours of frustration, I rebooted the computer, went for a run, came back, and tried again. It works!!! Thank you very much. --anonymouse
Jul 10 2022
prev sibling parent reply anonymouse <anany mouse.com> writes:
On Sunday, 10 July 2022 at 18:31:46 UTC, drug007 wrote:
 I'd like to say that using of exception to break loop is really 
 bad. Exception is exceptional thing but in the case above the 
 exception is ordinary completion of the loop happens on regular 
 basis. Don't do that.
Thanks for the advice. Lesson learned. --anonymouse
Jul 10 2022
parent reply jfondren <julian.fondren gmail.com> writes:
On Monday, 11 July 2022 at 03:17:33 UTC, anonymouse wrote:
 On Sunday, 10 July 2022 at 18:31:46 UTC, drug007 wrote:
 I'd like to say that using of exception to break loop is 
 really bad. Exception is exceptional thing but in the case 
 above the exception is ordinary completion of the loop happens 
 on regular basis. Don't do that.
Thanks for the advice. Lesson learned. --anonymouse
Oh, sorry. I didn't defend the code in any way because I assumed that the exceptional design would be seen as obviously bad (and that someone else would dig harder in order to find a better solution). The TypeInfo_Array fix breaks the last assertion of those unit tests, though. This works: ```d import std.variant : Variant; size_t[] shape(Variant v) { size_t[] s; while (cast(TypeInfo_Array) v.type !is null && v.length > 0) { Variant elem = v[0]; s ~= v.length; v = elem; } return s; } ``` Although, that last assertion really is debatable. Languages like APL would read it as having a shape of [2, 0]: ```d import std.variant : Variant; size_t[] shape(Variant v) { size_t[] s; while (cast(TypeInfo_Array) v.type !is null) { s ~= v.length; if (!v.length) break; v = v[0]; } return s; } unittest { assert([3, 1] == [[1], [2], [3]].Variant.shape); assert([2, 1] == [[1], [2]].Variant.shape); assert([2, 2] == [[1, 0], [2, 0]].Variant.shape); assert([2] == [1, 2].Variant.shape); assert([] == 2.Variant.shape); assert([2, 0] == [[], []].Variant.shape); // irregularity not checked assert([2, 2] == [[1, 0], [2]].Variant.shape); } ```
Jul 10 2022
parent reply anonymouse <anany mouse.com> writes:
On Monday, 11 July 2022 at 05:41:40 UTC, jfondren wrote:
 Oh, sorry. I didn't defend the code in any way because I 
 assumed that the exceptional design would be seen as obviously 
 bad (and that someone else would dig harder in order to find a 
 better solution).
And you were right. I did search for a better solution and came across [1]. Although I was having some issues adapting it for my use case, Paul Backus' follow-up clarified the issue. This is what my naive brain led to before reading this response. ```d size_t[] shape(Variant v) { typeof(return) dims; while(cast(TypeInfo_Array) v.type !is null) { dims ~= v.length; v = v[0]; } if(!dims.length && v.length) { dims ~= v.length; dims ~= 0; } return dims; } ``` Didn't see the bugs that would occur when a scalar or empty array was passed because I hadn't tested for them.
         if (!v.length) break;
Pure gold! Bugs are eliminated, and the code is shorter. Thank you. --anonymouse [1] https://tastyminerals.github.io/tasty-blog/dlang/2020/03/22/multidimensional_arrays_in_d.html
Jul 10 2022
parent Salih Dincer <salihdb hotmail.com> writes:
On Monday, 11 July 2022 at 06:59:32 UTC, anonymouse wrote:
 I did search for a better solution and came across...
 https://tastyminerals.github.io/tasty-blog/dlang/2020/03/22/multidimensional_arrays_in_d.html
I like it! It's been a good collaboration... ```d import std.variant; auto generate(T)(size_t x, size_t y) { T[][] result; ubyte[] arr = new ubyte[x * y * T.sizeof]; size_t m = y * T.sizeof;  foreach (i; 0 .. x) { size_t n = i * m;    result ~= cast(T[])arr[n .. n + m]; }  return result; } size_t[] shape(Variant v) {  typeof(return) dims;  while (cast(TypeInfo_Array) v.type !is null) {   dims ~= v.length; v = v[0]; }  if (!dims.length && v.length) {   dims ~= v.length; dims ~= 0; } return dims; } void main() {  foreach(x; 1..100) {    foreach(y; 1..100) {     auto test = Variant(generate!int(x, y));     assert(shape(test) == [x, y]);    }  } } ``` SDB 79
Jul 11 2022