www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Casting JSONValues arrays to native arrays ... ??? ...

reply james.p.leblanc <james.p.leblanc gmail.com> writes:
Dear D-ers,

In attempting to cast JSONValues that hold arrays to "native" 
array types,
I have hit some issues.  Example code:

```d
import std.stdio;
import std.json;

void main(){

    JSONValue jj;
    jj["d"] = [ 1.234 ];                  // a "dummy" double value
    jj["ba"] = [ true, false, true];      // "ba" boolean array

    writeln("typeid(jj): ", typeid(jj), ", jj: ", jj );

    // various things that I thought might work, but do NOT





    writeln("typeid(z4): ", typeid(z4), ", z4: ", z4 );

}
```
Attempts 1,2, and 3 yield compilation errors (which I somewhat 
understand):

question.d(12): Error: cannot cast expression `jj.opIndex("ba")` 
of type `JSONValue` to `bool`
question.d(13): Error: cannot cast expression `jj.opIndex("ba")` 
of type `JSONValue` to `bool[]`
question.d(14): Error: cannot cast expression 
`jj.opIndex("ba").array()` of type `JSONValue[]` to `bool`

However, if I comment out the offending attempts (1, 2, and 3), 
then it
compiles, and can run ... but produces a result which I very much 
do NOT
understand:

typeid(jj): std.json.JSONValue, jj: 
{"ba":[true,false,true],"d":[1.23399999999999999]}
typeid(z4): bool[], z4: [false, false, false, false, false, 
false, false, false, false, false, false, false, false, false, 
false, false, true, false, false, false, false, false, false, 
false, false, false, false, false, false, false, false, false, 
false, false, false, false, false, false, false, false, true, 
false, false, false, false, false, false, false, false, false, 
false, false, false, false, false, false, false, false, false, 
false, false, false, false, false, true, false, false, false, 
false, false, false, false]

Hmmmm... is there a standard way to push these JSONValues into 
nice native
array types? (The real code is eventually going to be using 
traits and mixins
... but I do not think this should pose additional problems).

All help and illumination thankfully received.
Best Regards,
James
Sep 23 2021
parent reply Steven Schveighoffer <schveiguy gmail.com> writes:
On 9/23/21 2:20 PM, james.p.leblanc wrote:
 Dear D-ers,
 
 In attempting to cast JSONValues that hold arrays to "native" array types,
 I have hit some issues.  Example code:
 
 ```d
 import std.stdio;
 import std.json;
 
 void main(){
 
     JSONValue jj;
     jj["d"] = [ 1.234 ];                  // a "dummy"
double value
     jj["ba"] = [ true, false, true];      // "ba" boolean array
Note that this creates a JSONValue array which *copies* the values of the boolean array, converting them to JSONValue (which is what a JSONValue array stores).
 
     writeln("typeid(jj): ", typeid(jj), ", jj: ", jj );
 
     // various things that I thought might work, but do NOT
 

A JSONValue cannot be cast to a boolean (it does not provide the appropriate opCast)


These try to cast something that is not an array to an array or vice versa. These are not supported unless the type itself has an `opCast` overload.

Casting one array type to another is like pointing at the array that represents the original type *as if* it were of the new type. No translation is made, you are pointing at the same memory! The length is adjusted based on the size of the original array element and the size of the new one. For instance: ```d int[] arr = [1]; auto a2 = cast(ubyte[])arr; assert(a2.length == 4); assert(a2 == cast(ubyte[])([1, 0, 0, 0])); // assuming little endian ```
 
 However, if I comment out the offending attempts (1, 2, and 3), then it
 compiles, and can run ... but produces a result which I very much do NOT
 understand:
 
 typeid(jj): std.json.JSONValue, jj: 
 {"ba":[true,false,true],"d":[1.23399999999999999]}
 typeid(z4): bool[], z4: [false, false, false, false, false, false, 
 false, false, false, false, false, false, false, false, false, false, 
 true, false, false, false, false, false, false, false, false, false, 
 false, false, false, false, false, false, false, false, false, false, 
 false, false, false, false, true, false, false, false, false, false, 
 false, false, false, false, false, false, false, false, false, false, 
 false, false, false, false, false, false, false, false, true, false, 
 false, false, false, false, false, false]
This is an array of JSONValue, with each byte interpreted as if it were a bool.
 Hmmmm... is there a standard way to push these JSONValues into nice native
 array types? (The real code is eventually going to be using traits and 
 mixins
 ... but I do not think this should pose additional problems).
How you really do this: ```d import std.algorithm : map; auto z5 = jj["ba"] // get the JSONValue that is at the key "ba" .map!(v => v.get!bool) // map each value into a boolean .array // create an array out of the results; assert z5 == [true, false, true]; ``` (warning, untested) -Steve
Sep 23 2021
parent reply james.p.leblanc <james.p.leblanc gmail.com> writes:
On Thursday, 23 September 2021 at 19:04:47 UTC, Steven 
Schveighoffer wrote:
 On 9/23/21 2:20 PM, james.p.leblanc wrote:
 Dear D-ers,
 
 In attempting to cast JSONValues that hold arrays to "native"
 How you really do this:

 ```d
 import std.algorithm : map;
 auto z5 = jj["ba"] // get the JSONValue that is at the key "ba"
       .map!(v => v.get!bool) // map each value into a boolean
       .array // create an array out of the results;
 assert z5 == [true, false, true];
 ```

 (warning, untested)

 -Steve
Steve, Your thorough explanations have helped me understand quite much. Thank you for your energy and patience in these forum contributions. In fact, I had begun to think that "map", may be what was needed here and I had made a few naive attempts ... but this did not go so well. With your suggested solution, I believe I can make headway on this. Thanks Again, James
Sep 23 2021
parent reply james.p.leblanc <james.p.leblanc gmail.com> writes:
On Thursday, 23 September 2021 at 19:18:11 UTC, james.p.leblanc 
wrote:
 On Thursday, 23 September 2021 at 19:04:47 UTC, Steven 
 Schveighoffer wrote:
 On 9/23/21 2:20 PM, james.p.leblanc wrote:
 Dear D-ers,
 
Here comes a minor update (small rearrangement in mapping/array ordering) for anyone who may be interested. With this small edit to the suggested code, it works just fine! Here: ```d auto z5 = jj["ba"].array.map!(v => v.get!bool); writeln("typeid(z5): ", typeid(z5), ", z5: ", z5); writeln("z5: ", z5); ``` Produces: typeid(jj): std.json.JSONValue, jj: {"ba":[true,false,true],"d":[1.23399999999999999]} typeid(z5): question.main.MapResult!(__lambda2, JSONValue[]).MapResult, z5: [true, false, true] z5: [true, false, true] Cheers, James
Sep 23 2021
parent reply james.p.leblanc <james.p.leblanc gmail.com> writes:
On Thursday, 23 September 2021 at 20:32:36 UTC, james.p.leblanc 
wrote:
 On Thursday, 23 September 2021 at 19:18:11 UTC, james.p.leblanc 
 wrote:
 On Thursday, 23 September 2021 at 19:04:47 UTC, Steven 
 Schveighoffer wrote:
 On 9/23/21 2:20 PM, james.p.leblanc wrote:
``` Produces: typeid(jj): std.json.JSONValue, jj: {"ba":[true,false,true],"d":[1.23399999999999999]} typeid(z5): question.main.MapResult!(__lambda2, JSONValue[]).MapResult, z5: [true, false, true] z5: [true, false, true]
Sigh ... my suggested "minor edit" above produces a "map result" instead of the desired native array ... here is the **fix** by appending ".array" at the end (which is the suffix Steve originally offered). The following gives the desired **bool[]** result. ```d import std.array; auto z5 = jj["ba"].array.map!(v => v.get!bool).array; writeln("typeid(z5): ", typeid(z5), ", z5: ", z5); writeln("z5: ", z5); ``` Regards, James
Sep 23 2021
parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 9/24/21 12:58 AM, james.p.leblanc wrote:
 On Thursday, 23 September 2021 at 20:32:36 UTC, james.p.leblanc wrote:
 On Thursday, 23 September 2021 at 19:18:11 UTC, james.p.leblanc wrote:
 On Thursday, 23 September 2021 at 19:04:47 UTC, Steven Schveighoffer 
 wrote:
 On 9/23/21 2:20 PM, james.p.leblanc wrote:
``` Produces: typeid(jj): std.json.JSONValue, jj: {"ba":[true,false,true],"d":[1.23399999999999999]} typeid(z5): question.main.MapResult!(__lambda2, JSONValue[]).MapResult, z5: [true, false, true] z5: [true, false, true]
Sigh ... my suggested "minor edit" above produces a "map result" instead of the desired native array ... here is the **fix** by appending ".array" at the end (which is the suffix Steve originally offered).  The following gives the desired **bool[]** result. ```d import std.array;    auto z5 = jj["ba"].array.map!(v => v.get!bool).array;    writeln("typeid(z5): ", typeid(z5), ", z5: ", z5);    writeln("z5: ", z5); ```
At first I thought that was allocating 2 arrays, but I didn't realize `JSONValue.array` was an actual member! When I saw your original code, I assumed the `.array` call was a call to `std.array.array`, and that `JSONValue` was somehow usable as a range. So yes, that's what I should have written. I admit I have not used `JSONValue`. That `array` accessor is quite a poor name due to the vast prevalence of using `std.array.array` to make an array out of some range. When using vibe.d's JSON type, I usually do `jsval[]` to access the array portion. Note, you may want to consider whether you actually need a concrete array, as using the map result is pretty much equivalent, yet doesn't allocate anything. -STeve
Sep 24 2021