www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - D JSON (WAT?!)

reply "Pavel" <nomail noplace.org> writes:
Ok, let me start with the sample code:

import std.stdio;
import std.json;

void main() {
   scope(failure) writeln("FaILED!!");
   string jsonStr = `{ "name": "1", "type": "r" }`;
   auto parsed = parseJSON(jsonStr);
   string s = parsed["fail"].str;
   writeln(s == "");
   writeln(s is null);
   writeln(s);
}

Running "rdmd app.d" doesn't produce any output.
Can anyone explain such a behavior???


PS: Running dmd v2.065 on Linux x64.
Jul 24 2014
next sibling parent reply Justin Whear <justin economicmodeling.com> writes:
On Thu, 24 Jul 2014 15:15:36 +0000, Pavel wrote:

 Ok, let me start with the sample code:
 
 import std.stdio;
 import std.json;
 
 void main() {
    scope(failure) writeln("FaILED!!");
    string jsonStr = `{ "name": "1", "type": "r" }`;
    auto parsed = parseJSON(jsonStr);
    string s = parsed["fail"].str;
    writeln(s == "");
    writeln(s is null);
    writeln(s);
 }
 
 Running "rdmd app.d" doesn't produce any output.
 Can anyone explain such a behavior???
 
 
 PS: Running dmd v2.065 on Linux x64.
That's because it produces a segmentation fault, which rdmd masks for some reason. The `parsed["fail"]` should throw a range bounds exception-- not sure why it's not.
Jul 24 2014
parent "Pavel" <nomail noplace.org> writes:
On Thursday, 24 July 2014 at 15:20:58 UTC, Justin Whear wrote:
 On Thu, 24 Jul 2014 15:15:36 +0000, Pavel wrote:

 Ok, let me start with the sample code:
 
 import std.stdio;
 import std.json;
 
 void main() {
    scope(failure) writeln("FaILED!!");
    string jsonStr = `{ "name": "1", "type": "r" }`;
    auto parsed = parseJSON(jsonStr);
    string s = parsed["fail"].str;
    writeln(s == "");
    writeln(s is null);
    writeln(s);
 }
 
 Running "rdmd app.d" doesn't produce any output.
 Can anyone explain such a behavior???
 
 
 PS: Running dmd v2.065 on Linux x64.
That's because it produces a segmentation fault, which rdmd masks for some reason. The `parsed["fail"]` should throw a range bounds exception-- not sure why it's not.
Here's phobos code from github: /// Hash syntax for json objects. /// Throws $(D JSONException) if $(D type) is not $(D JSON_TYPE.OBJECT). ref inout(JSONValue) opIndex(string k) inout { enforceEx!JSONException(type == JSON_TYPE.OBJECT, "JSONValue is not an object"); return *enforceEx!JSONException(k in store.object, "Key not found: " ~ k); } Added in https://github.com/D-Programming-Language/phobos/commit/13fbd451bcca923cf8d1028495e58aa88cc7efeb Maybe phobos is not up to date for me???
Jul 24 2014
prev sibling next sibling parent reply "Adam D. Ruppe" <destructionator gmail.com> writes:
On Thursday, 24 July 2014 at 15:15:37 UTC, Pavel wrote:
   string s = parsed["fail"].str;
Since there is no entry "fail" in the object, it returns a null JSON_VALUE pointer. Trying to get the string out of it is then seen as a null pointer access and kills the program. Check for null on a key before trying to get a value out.
Jul 24 2014
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Adam D. Ruppe:

 Check for null on a key before trying to get a value out.
Is something like the get() function usable here? Bye, bearophile
Jul 24 2014
prev sibling parent reply "Pavel" <nomail noplace.org> writes:
On Thursday, 24 July 2014 at 15:22:46 UTC, Adam D. Ruppe wrote:
 On Thursday, 24 July 2014 at 15:15:37 UTC, Pavel wrote:
  string s = parsed["fail"].str;
Since there is no entry "fail" in the object, it returns a null JSON_VALUE pointer. Trying to get the string out of it is then seen as a null pointer access and kills the program. Check for null on a key before trying to get a value out.
Ok, added: writeln(parsed["fail"] == null); Now compiler complains: Error: incompatible types for ((parsed.opIndex("fail")) == (null)): 'JSONValue' and 'typeof(null)' WAT?!
Jul 24 2014
next sibling parent reply Daniel Gibson <metalcaedes gmail.com> writes:
Am 24.07.2014 17:29, schrieb Pavel:
 On Thursday, 24 July 2014 at 15:22:46 UTC, Adam D. Ruppe wrote:
 On Thursday, 24 July 2014 at 15:15:37 UTC, Pavel wrote:
  string s = parsed["fail"].str;
Since there is no entry "fail" in the object, it returns a null JSON_VALUE pointer. Trying to get the string out of it is then seen as a null pointer access and kills the program. Check for null on a key before trying to get a value out.
Ok, added: writeln(parsed["fail"] == null); Now compiler complains: Error: incompatible types for ((parsed.opIndex("fail")) == (null)): 'JSONValue' and 'typeof(null)' WAT?!
"is" instead of "==" ?
Jul 24 2014
parent "Pavel" <nomail noplace.org> writes:
On Thursday, 24 July 2014 at 15:31:30 UTC, Daniel Gibson wrote:
 Am 24.07.2014 17:29, schrieb Pavel:
 On Thursday, 24 July 2014 at 15:22:46 UTC, Adam D. Ruppe wrote:
 On Thursday, 24 July 2014 at 15:15:37 UTC, Pavel wrote:
 string s = parsed["fail"].str;
Since there is no entry "fail" in the object, it returns a null JSON_VALUE pointer. Trying to get the string out of it is then seen as a null pointer access and kills the program. Check for null on a key before trying to get a value out.
Ok, added: writeln(parsed["fail"] == null); Now compiler complains: Error: incompatible types for ((parsed.opIndex("fail")) == (null)): 'JSONValue' and 'typeof(null)' WAT?!
"is" instead of "==" ?
Nope, the compiler still complains.
Jul 24 2014
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 07/24/2014 08:29 AM, Pavel wrote:

 writeln(parsed["fail"] == null);

 Now compiler complains:

 Error: incompatible types for ((parsed.opIndex("fail")) == (null)):
 'JSONValue' and 'typeof(null)'


 WAT?!
Comparing against null should be done with the 'is' operator, not the == operator: if (x is null) Ali
Jul 24 2014
parent "Pavel" <nomail noplace.org> writes:
On Thursday, 24 July 2014 at 15:34:22 UTC, Ali Çehreli wrote:
 On 07/24/2014 08:29 AM, Pavel wrote:

 writeln(parsed["fail"] == null);

 Now compiler complains:

 Error: incompatible types for ((parsed.opIndex("fail")) == 
 (null)):
 'JSONValue' and 'typeof(null)'


 WAT?!
Comparing against null should be done with the 'is' operator, not the == operator: if (x is null) Ali
My compiler disagreed: app.d(8): Error: incompatible types for ((parsed.opIndex("fail")) is (null)): 'JSONValue' and 'typeof(null)'
Jul 24 2014
prev sibling parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Thursday, 24 July 2014 at 15:15:37 UTC, Pavel wrote:
 Ok, let me start with the sample code:

 import std.stdio;
 import std.json;

 void main() {
   scope(failure) writeln("FaILED!!");
   string jsonStr = `{ "name": "1", "type": "r" }`;
   auto parsed = parseJSON(jsonStr);
   string s = parsed["fail"].str;
   writeln(s == "");
   writeln(s is null);
   writeln(s);
 }

 Running "rdmd app.d" doesn't produce any output.
 Can anyone explain such a behavior???


 PS: Running dmd v2.065 on Linux x64.
It's a bug in std.json (you should get a segfault, not no output at all) It is fixed now and I'm pretty sure it will be in 2.066 std.json has been improved a lot, but I would still recommend using http://vibed.org/api/vibe.data.json/ instead
Jul 24 2014
next sibling parent reply "John Colvin" <john.loughran.colvin gmail.com> writes:
On Thursday, 24 July 2014 at 15:32:29 UTC, John Colvin wrote:
 On Thursday, 24 July 2014 at 15:15:37 UTC, Pavel wrote:
 Ok, let me start with the sample code:

 import std.stdio;
 import std.json;

 void main() {
  scope(failure) writeln("FaILED!!");
  string jsonStr = `{ "name": "1", "type": "r" }`;
  auto parsed = parseJSON(jsonStr);
  string s = parsed["fail"].str;
  writeln(s == "");
  writeln(s is null);
  writeln(s);
 }

 Running "rdmd app.d" doesn't produce any output.
 Can anyone explain such a behavior???


 PS: Running dmd v2.065 on Linux x64.
It's a bug in std.json (you should get a segfault, not no output at all) It is fixed now and I'm pretty sure it will be in 2.066 std.json has been improved a lot, but I would still recommend using http://vibed.org/api/vibe.data.json/ instead
perhaps "bug" is too strong a word, but it was a deficiency that is now corrected. You will get an exception thrown now and everything should work how you expect.
Jul 24 2014
parent reply "Pavel" <nomail noplace.org> writes:
On Thursday, 24 July 2014 at 15:38:06 UTC, John Colvin wrote:
 On Thursday, 24 July 2014 at 15:32:29 UTC, John Colvin wrote:
 On Thursday, 24 July 2014 at 15:15:37 UTC, Pavel wrote:
 Ok, let me start with the sample code:

 import std.stdio;
 import std.json;

 void main() {
 scope(failure) writeln("FaILED!!");
 string jsonStr = `{ "name": "1", "type": "r" }`;
 auto parsed = parseJSON(jsonStr);
 string s = parsed["fail"].str;
 writeln(s == "");
 writeln(s is null);
 writeln(s);
 }

 Running "rdmd app.d" doesn't produce any output.
 Can anyone explain such a behavior???


 PS: Running dmd v2.065 on Linux x64.
It's a bug in std.json (you should get a segfault, not no output at all) It is fixed now and I'm pretty sure it will be in 2.066 std.json has been improved a lot, but I would still recommend using http://vibed.org/api/vibe.data.json/ instead
perhaps "bug" is too strong a word, but it was a deficiency that is now corrected. You will get an exception thrown now and everything should work how you expect.
Maybe. But still it's not the way I expect, any time you check for non-existing property you must consider exception, which is very heavy to deal with in such a situation. I'd rather expect to get null, whenever I try to fetch non-existing property, and not an exception. That's purely my point, and I don't claim to be right in this way. It's up to Phobos maintainers to decide how to reprent JSON parsing results.
Jul 24 2014
next sibling parent "Pavel" <nomail noplace.org> writes:
On Thursday, 24 July 2014 at 15:42:58 UTC, Pavel wrote:
 On Thursday, 24 July 2014 at 15:38:06 UTC, John Colvin wrote:
 On Thursday, 24 July 2014 at 15:32:29 UTC, John Colvin wrote:
 On Thursday, 24 July 2014 at 15:15:37 UTC, Pavel wrote:
 Ok, let me start with the sample code:

 import std.stdio;
 import std.json;

 void main() {
 scope(failure) writeln("FaILED!!");
 string jsonStr = `{ "name": "1", "type": "r" }`;
 auto parsed = parseJSON(jsonStr);
 string s = parsed["fail"].str;
 writeln(s == "");
 writeln(s is null);
 writeln(s);
 }

 Running "rdmd app.d" doesn't produce any output.
 Can anyone explain such a behavior???


 PS: Running dmd v2.065 on Linux x64.
It's a bug in std.json (you should get a segfault, not no output at all) It is fixed now and I'm pretty sure it will be in 2.066 std.json has been improved a lot, but I would still recommend using http://vibed.org/api/vibe.data.json/ instead
perhaps "bug" is too strong a word, but it was a deficiency that is now corrected. You will get an exception thrown now and everything should work how you expect.
Maybe. But still it's not the way I expect, any time you check for non-existing property you must consider exception, which is very heavy to deal with in such a situation. I'd rather expect to get null, whenever I try to fetch non-existing property, and not an exception. That's purely my point, and I don't claim to be right in this way. It's up to Phobos maintainers to decide how to reprent JSON parsing results.
Also that's why you just can't write: writeln("fail" in parsed); As JSONValue is just a wrapper: non-native, non-intuitive.
Jul 24 2014
prev sibling parent reply "Edwin van Leeuwen" <edder tkwsping.nl> writes:
On Thursday, 24 July 2014 at 15:42:58 UTC, Pavel wrote:
 On Thursday, 24 July 2014 at 15:38:06 UTC, John Colvin wrote:
 On Thursday, 24 July 2014 at 15:32:29 UTC, John Colvin wrote:
 On Thursday, 24 July 2014 at 15:15:37 UTC, Pavel wrote:
 Ok, let me start with the sample code:

 import std.stdio;
 import std.json;

 void main() {
 scope(failure) writeln("FaILED!!");
 string jsonStr = `{ "name": "1", "type": "r" }`;
 auto parsed = parseJSON(jsonStr);
 string s = parsed["fail"].str;
 writeln(s == "");
 writeln(s is null);
 writeln(s);
 }

 Running "rdmd app.d" doesn't produce any output.
 Can anyone explain such a behavior???


 PS: Running dmd v2.065 on Linux x64.
It's a bug in std.json (you should get a segfault, not no output at all) It is fixed now and I'm pretty sure it will be in 2.066 std.json has been improved a lot, but I would still recommend using http://vibed.org/api/vibe.data.json/ instead
perhaps "bug" is too strong a word, but it was a deficiency that is now corrected. You will get an exception thrown now and everything should work how you expect.
Maybe. But still it's not the way I expect, any time you check for non-existing property you must consider exception, which is very heavy to deal with in such a situation. I'd rather expect to get null, whenever I try to fetch non-existing property, and not an exception.
You can turn your json object into an AA object and then use in to check for existence (I know it is not very intuitive): JSONValue[string] jsonAA = parsed.object; if ( "fail" in jsonAA ) s = jsonAA["fail"].str;
 That's purely my point, and I don't claim to be right in this 
 way. It's up to Phobos maintainers to decide how to reprent 
 JSON parsing results.
Jul 24 2014
parent reply "Pavel" <nomail noplace.org> writes:
On Thursday, 24 July 2014 at 15:48:32 UTC, Edwin van Leeuwen 
wrote:
 On Thursday, 24 July 2014 at 15:42:58 UTC, Pavel wrote:
 On Thursday, 24 July 2014 at 15:38:06 UTC, John Colvin wrote:
 On Thursday, 24 July 2014 at 15:32:29 UTC, John Colvin wrote:
 On Thursday, 24 July 2014 at 15:15:37 UTC, Pavel wrote:
 Ok, let me start with the sample code:

 import std.stdio;
 import std.json;

 void main() {
 scope(failure) writeln("FaILED!!");
 string jsonStr = `{ "name": "1", "type": "r" }`;
 auto parsed = parseJSON(jsonStr);
 string s = parsed["fail"].str;
 writeln(s == "");
 writeln(s is null);
 writeln(s);
 }

 Running "rdmd app.d" doesn't produce any output.
 Can anyone explain such a behavior???


 PS: Running dmd v2.065 on Linux x64.
It's a bug in std.json (you should get a segfault, not no output at all) It is fixed now and I'm pretty sure it will be in 2.066 std.json has been improved a lot, but I would still recommend using http://vibed.org/api/vibe.data.json/ instead
perhaps "bug" is too strong a word, but it was a deficiency that is now corrected. You will get an exception thrown now and everything should work how you expect.
Maybe. But still it's not the way I expect, any time you check for non-existing property you must consider exception, which is very heavy to deal with in such a situation. I'd rather expect to get null, whenever I try to fetch non-existing property, and not an exception.
You can turn your json object into an AA object and then use in to check for existence (I know it is not very intuitive): JSONValue[string] jsonAA = parsed.object; if ( "fail" in jsonAA ) s = jsonAA["fail"].str;
 That's purely my point, and I don't claim to be right in this 
 way. It's up to Phobos maintainers to decide how to reprent 
 JSON parsing results.
Guess what, here's a new snippet: import std.stdio; import std.json; void main() { scope(failure) writeln("FaILED!!"); string jsonStr = `{ "name": "1", "type": "r" }`; auto parsed = parseJSON(jsonStr).object; writeln("fail" in parsed); } Output is: null WAT?! Ofcourse, writing like: writeln(cast(bool)("fail" in parsed)); Produces "false"... but why on earth boolean expression would output null? PS: Sorry, for such an emotional boom, I'm so frustrated right now.
Jul 24 2014
next sibling parent "bearophile" <bearophileHUGS lycos.com> writes:
Pavel:

 writeln(cast(bool)("fail" in parsed));

 Produces "false"... but why on earth boolean expression would 
 output null?
In D if you perform an associative array "in", the return isn't a boolean but a pointer. It's zero if the item is not present. And it's a valid pointer to the value if the key is present. Bye, bearophile
Jul 24 2014
prev sibling next sibling parent reply Daniel Gibson <metalcaedes gmail.com> writes:
Am 24.07.2014 17:54, schrieb Pavel:
 Guess what, here's a new snippet:

 import std.stdio;
 import std.json;

 void main() {
    scope(failure) writeln("FaILED!!");
    string jsonStr = `{ "name": "1", "type": "r" }`;
    auto parsed = parseJSON(jsonStr).object;
    writeln("fail" in parsed);
 }

 Output is:
 null

 WAT?!

 Ofcourse, writing like:

 writeln(cast(bool)("fail" in parsed));

 Produces "false"... but why on earth boolean expression would output null?

 PS: Sorry, for such an emotional boom, I'm so frustrated right now.
Relax :-) And see http://dlang.org/hash-map.html "in" doesn't just return if something is in a map. If it is, it returns a pointer to the value, otherwise null. Thus null. Cheers, Daniel
Jul 24 2014
parent reply "Pavel" <nomail noplace.org> writes:
On Thursday, 24 July 2014 at 15:59:52 UTC, Daniel Gibson wrote:
 Am 24.07.2014 17:54, schrieb Pavel:
 Guess what, here's a new snippet:

 import std.stdio;
 import std.json;

 void main() {
   scope(failure) writeln("FaILED!!");
   string jsonStr = `{ "name": "1", "type": "r" }`;
   auto parsed = parseJSON(jsonStr).object;
   writeln("fail" in parsed);
 }

 Output is:
 null

 WAT?!

 Ofcourse, writing like:

 writeln(cast(bool)("fail" in parsed));

 Produces "false"... but why on earth boolean expression would 
 output null?

 PS: Sorry, for such an emotional boom, I'm so frustrated right 
 now.
Relax :-) And see http://dlang.org/hash-map.html "in" doesn't just return if something is in a map. If it is, it returns a pointer to the value, otherwise null. Thus null. Cheers, Daniel
Thanks to all you folks who explained "in" operator for me. My bad. Let's focus on the real problem, which is JSON wrapper class. Is it needed? Wouldn't it be better to get AA from parseJSON?
Jul 24 2014
parent reply Justin Whear <justin economicmodeling.com> writes:
On Thu, 24 Jul 2014 16:04:01 +0000, Pavel wrote:
 
 Thanks to all you folks who explained "in" operator for me. My bad.
 Let's focus on the real problem, which is JSON wrapper class. Is it
 needed? Wouldn't it be better to get AA from parseJSON?
The following are valid JSON: auto json1 = parseJSON(`1`); auto json2 = parseJSON(`"foo"`); auto json3 = parseJSON(`[1, 2, 3]`); None of these fit naturally into an JSONValue[string] return type.
Jul 24 2014
next sibling parent reply "Pavel" <nomail noplace.org> writes:
On Thursday, 24 July 2014 at 16:09:25 UTC, Justin Whear wrote:
 On Thu, 24 Jul 2014 16:04:01 +0000, Pavel wrote:
 
 Thanks to all you folks who explained "in" operator for me. My 
 bad.
 Let's focus on the real problem, which is JSON wrapper class. 
 Is it
 needed? Wouldn't it be better to get AA from parseJSON?
The following are valid JSON: auto json1 = parseJSON(`1`); auto json2 = parseJSON(`"foo"`); auto json3 = parseJSON(`[1, 2, 3]`); None of these fit naturally into an JSONValue[string] return type.
Oh, man! You're wrong!!! Read: http://www.json.org/, and try putting "1" or "foo" as JSON string here: http://jsonlint.com/
Jul 24 2014
parent Justin Whear <justin economicmodeling.com> writes:
On Thu, 24 Jul 2014 16:14:15 +0000, Pavel wrote:

 On Thursday, 24 July 2014 at 16:09:25 UTC, Justin Whear wrote:
 On Thu, 24 Jul 2014 16:04:01 +0000, Pavel wrote:
 
 Thanks to all you folks who explained "in" operator for me. My bad.
 Let's focus on the real problem, which is JSON wrapper class. Is it
 needed? Wouldn't it be better to get AA from parseJSON?
The following are valid JSON: auto json1 = parseJSON(`1`); auto json2 = parseJSON(`"foo"`); auto json3 = parseJSON(`[1, 2, 3]`); None of these fit naturally into an JSONValue[string] return type.
Oh, man! You're wrong!!! Read: http://www.json.org/, and try putting "1" or "foo" as JSON string here: http://jsonlint.com/
Nope, while the spec calls out objects and arrays as the structural elements of JSON, it never requires (anywhere that I can find) that a complete JSON document have one of these at the root. A valid JSON value is defined as "A JSON value can be an object, array, number, string, true, false, or null"[1] Thus the parseJSON function is defined as parsing as JSONValue. 1 http://www.ecma-international.org/publications/files/ECMA-ST/ ECMA-404.pdf, p2
Jul 24 2014
prev sibling next sibling parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
On 7/24/14, 1:09 PM, Justin Whear wrote:
 On Thu, 24 Jul 2014 16:04:01 +0000, Pavel wrote:
 Thanks to all you folks who explained "in" operator for me. My bad.
 Let's focus on the real problem, which is JSON wrapper class. Is it
 needed? Wouldn't it be better to get AA from parseJSON?
The following are valid JSON: auto json1 = parseJSON(`1`); auto json2 = parseJSON(`"foo"`); auto json3 = parseJSON(`[1, 2, 3]`); None of these fit naturally into an JSONValue[string] return type.
Nope, a JSON can only be an array or an object (hash). In Crystal we have this definition: alias JsonType = Nil | Bool | Int64 | Float64 | String | Array(JsonType) | Hash(String, JsonType) (note that this is a recursive type definition) Then when you do Json.parse you get a value whose type is Array(JsonType) | Hash(String, JsonType). The good thing about this is that Json.parse gives you types that already exist: Array, Hash, Int64, etc. No need to define extra types and no need for users to learn a new API with new types. Wouldn't something like this be better to do in D? That is, return something that is an array or an associative array...
Jul 24 2014
parent reply Justin Whear <justin economicmodeling.com> writes:
On Thu, 24 Jul 2014 13:49:27 -0300, Ary Borenszweig wrote:

 Nope, a JSON can only be an array or an object (hash).
Ary, can you point out the place in the spec where this is specified? Not to be pedantic, but the spec only seems to define a "JSON value", not a "JSON document".
Jul 24 2014
parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
On 7/24/14, 1:58 PM, Justin Whear wrote:
 On Thu, 24 Jul 2014 13:49:27 -0300, Ary Borenszweig wrote:

 Nope, a JSON can only be an array or an object (hash).
Ary, can you point out the place in the spec where this is specified? Not to be pedantic, but the spec only seems to define a "JSON value", not a "JSON document".
You are right, my bad. According to Wikipedia (which has links to RFCs): Early versions of JSON (such as specified by RFC 4627) required that a valid JSON "document" must consist of only an object or an array type—though they could contain other types within them. This restriction was relaxed starting with RFC 7158, so that a JSON document may consist entirely of any possible JSON typed value.
Jul 24 2014
parent "Pavel" <nomail noplace.org> writes:
On Thursday, 24 July 2014 at 18:49:27 UTC, Ary Borenszweig wrote:
 On 7/24/14, 1:58 PM, Justin Whear wrote:
 On Thu, 24 Jul 2014 13:49:27 -0300, Ary Borenszweig wrote:

 Nope, a JSON can only be an array or an object (hash).
Ary, can you point out the place in the spec where this is specified? Not to be pedantic, but the spec only seems to define a "JSON value", not a "JSON document".
You are right, my bad. According to Wikipedia (which has links to RFCs): Early versions of JSON (such as specified by RFC 4627) required that a valid JSON "document" must consist of only an object or an array type—though they could contain other types within them. This restriction was relaxed starting with RFC 7158, so that a JSON document may consist entirely of any possible JSON typed value.
Sorry, Justin Whear, you were right, I was wrong. Yep, now it's pretty clear why there is JSONValue.
Jul 24 2014
prev sibling next sibling parent reply "Pavel" <nomail noplace.org> writes:
On Thursday, 24 July 2014 at 16:09:25 UTC, Justin Whear wrote:
 On Thu, 24 Jul 2014 16:04:01 +0000, Pavel wrote:
 
 Thanks to all you folks who explained "in" operator for me. My 
 bad.
 Let's focus on the real problem, which is JSON wrapper class. 
 Is it
 needed? Wouldn't it be better to get AA from parseJSON?
The following are valid JSON: auto json1 = parseJSON(`1`); auto json2 = parseJSON(`"foo"`); auto json3 = parseJSON(`[1, 2, 3]`); None of these fit naturally into an JSONValue[string] return type.
Now we figured it out about JSON, but in that case: Why not just use std.variant.Variant construct instead of JSONValue?
Jul 24 2014
next sibling parent reply Justin Whear <justin economicmodeling.com> writes:
On Thu, 24 Jul 2014 22:00:43 +0000, Pavel wrote:

 On Thursday, 24 July 2014 at 16:09:25 UTC, Justin Whear wrote:
 On Thu, 24 Jul 2014 16:04:01 +0000, Pavel wrote:
 
 Thanks to all you folks who explained "in" operator for me. My bad.
 Let's focus on the real problem, which is JSON wrapper class. Is it
 needed? Wouldn't it be better to get AA from parseJSON?
The following are valid JSON: auto json1 = parseJSON(`1`); auto json2 = parseJSON(`"foo"`); auto json3 = parseJSON(`[1, 2, 3]`); None of these fit naturally into an JSONValue[string] return type.
Now we figured it out about JSON, but in that case: Why not just use std.variant.Variant construct instead of JSONValue?
While I suspect the reason is simply historical, it might be a type- safety/information problem as well. Variant can store values of essentially any type whereas JSON is strictly limited to a handful of simple types. Going from a JSON string to Variant might not be troublesome, but going from Variant to JSON string almost certainly would. That said, if you think it's worth it, I'd be up for reviewing a revamped std.json.
Jul 25 2014
parent reply Ary Borenszweig <ary esperanto.org.ar> writes:
On 7/25/14, 1:06 PM, Justin Whear wrote:
 On Thu, 24 Jul 2014 22:00:43 +0000, Pavel wrote:

 On Thursday, 24 July 2014 at 16:09:25 UTC, Justin Whear wrote:
 On Thu, 24 Jul 2014 16:04:01 +0000, Pavel wrote:
 Thanks to all you folks who explained "in" operator for me. My bad.
 Let's focus on the real problem, which is JSON wrapper class. Is it
 needed? Wouldn't it be better to get AA from parseJSON?
The following are valid JSON: auto json1 = parseJSON(`1`); auto json2 = parseJSON(`"foo"`); auto json3 = parseJSON(`[1, 2, 3]`); None of these fit naturally into an JSONValue[string] return type.
Now we figured it out about JSON, but in that case: Why not just use std.variant.Variant construct instead of JSONValue?
While I suspect the reason is simply historical, it might be a type- safety/information problem as well. Variant can store values of essentially any type whereas JSON is strictly limited to a handful of simple types. Going from a JSON string to Variant might not be troublesome, but going from Variant to JSON string almost certainly would. That said, if you think it's worth it, I'd be up for reviewing a revamped std.json.
Or use Algebraic, but it currently doesn't support recursive type definitions. I think this would be the best way.
Jul 25 2014
parent "Meta" <jared771 gmail.com> writes:
On Saturday, 26 July 2014 at 00:26:08 UTC, Ary Borenszweig wrote:
 Or use Algebraic, but it currently doesn't support recursive 
 type definitions.
Algebraic does support recursive type definitions. import std.variant; alias Rec = Algebraic!(int, This*); void main() { //I'm not sure why this works auto i = Rec(Rec(Rec(1))); i = Rec(new Rec(new Rec(1))); }
Jul 25 2014
prev sibling parent "Kagamin" <spam here.lot> writes:
AFAIK, Variant is not transparent. You can't write 
parsed["field1"]["field2"], it should be 
parsed["field1"].get!(Variant[string])["field2"].
Jul 26 2014
prev sibling parent reply "Pavel" <nomail noplace.org> writes:
On Thursday, 24 July 2014 at 16:09:25 UTC, Justin Whear wrote:
 On Thu, 24 Jul 2014 16:04:01 +0000, Pavel wrote:
 
 Thanks to all you folks who explained "in" operator for me. My 
 bad.
 Let's focus on the real problem, which is JSON wrapper class. 
 Is it
 needed? Wouldn't it be better to get AA from parseJSON?
The following are valid JSON: auto json1 = parseJSON(`1`); auto json2 = parseJSON(`"foo"`); auto json3 = parseJSON(`[1, 2, 3]`); None of these fit naturally into an JSONValue[string] return type.
auto json4 = parseJSON(`true`); This is a valid JSON also. I know that as per JSON spec there's no boolean type specified, only separate true and false values, which are specified as type in http://dlang.org/library/std/json/JSON_TYPE.html, so I guess the only way to check boolean in JSONValue it is to write: if (json4.type == JSON_TYPE.True) { } else { } Am I right?
Aug 08 2014
parent Justin Whear <justin economicmodeling.com> writes:
On Fri, 08 Aug 2014 14:07:33 +0000, Pavel wrote:

 
 I know that as per JSON spec there's no boolean type specified, only
 separate true and false values, which are specified as type in
 http://dlang.org/library/std/json/JSON_TYPE.html, so I guess the only
 way to check boolean in JSONValue it is to write:
 
 if (json4.type == JSON_TYPE.True) {
 } else {
 }
 
 Am I right?
That's right. Perhaps we need an `asBool` function or even an opCast!bool that returns false on FALSE, NULL, and possibly empty strings/ objects/arrays.
Aug 08 2014
prev sibling next sibling parent Justin Whear <justin economicmodeling.com> writes:
On Thu, 24 Jul 2014 15:54:20 +0000, Pavel wrote:

 On Thursday, 24 July 2014 at 15:48:32 UTC, Edwin van Leeuwen wrote:
 On Thursday, 24 July 2014 at 15:42:58 UTC, Pavel wrote:
 On Thursday, 24 July 2014 at 15:38:06 UTC, John Colvin wrote:
 On Thursday, 24 July 2014 at 15:32:29 UTC, John Colvin wrote:
 On Thursday, 24 July 2014 at 15:15:37 UTC, Pavel wrote:
 Ok, let me start with the sample code:

 import std.stdio;
 import std.json;

 void main() {
 scope(failure) writeln("FaILED!!");
 string jsonStr = `{ "name": "1", "type": "r" }`;
 auto parsed = parseJSON(jsonStr);
 string s = parsed["fail"].str;
 writeln(s == "");
 writeln(s is null);
 writeln(s);
 }

 Running "rdmd app.d" doesn't produce any output.
 Can anyone explain such a behavior???


 PS: Running dmd v2.065 on Linux x64.
It's a bug in std.json (you should get a segfault, not no output at all) It is fixed now and I'm pretty sure it will be in 2.066 std.json has been improved a lot, but I would still recommend using http://vibed.org/api/vibe.data.json/ instead
perhaps "bug" is too strong a word, but it was a deficiency that is now corrected. You will get an exception thrown now and everything should work how you expect.
Maybe. But still it's not the way I expect, any time you check for non-existing property you must consider exception, which is very heavy to deal with in such a situation. I'd rather expect to get null, whenever I try to fetch non-existing property, and not an exception.
You can turn your json object into an AA object and then use in to check for existence (I know it is not very intuitive): JSONValue[string] jsonAA = parsed.object; if ( "fail" in jsonAA ) s = jsonAA["fail"].str;
 That's purely my point, and I don't claim to be right in this way.
 It's up to Phobos maintainers to decide how to reprent JSON parsing
 results.
Guess what, here's a new snippet: import std.stdio; import std.json; void main() { scope(failure) writeln("FaILED!!"); string jsonStr = `{ "name": "1", "type": "r" }`; auto parsed = parseJSON(jsonStr).object; writeln("fail" in parsed); } Output is: null WAT?! Ofcourse, writing like: writeln(cast(bool)("fail" in parsed)); Produces "false"... but why on earth boolean expression would output null? PS: Sorry, for such an emotional boom, I'm so frustrated right now.
The `in` expression produces a pointer to the value in the container, not a bool. If the key is not present in the container, it returns the null pointer. So this test is working precisely as expected. Here are some common idioms for working with `in` and associative arrays: // if with declaration if (auto vptr = "fail" in parsed.object) writeln("here's the value: ", *vptr); else writeln("fail is not in the JSON"); // coerce to bool writeln(!!("fail" in parsed.object)); // get the value or a default value writeln(parsed.object.get("fail", someDefaultJson));
Jul 24 2014
prev sibling next sibling parent reply "H. S. Teoh via Digitalmars-d-learn" <digitalmars-d-learn puremagic.com> writes:
On Thu, Jul 24, 2014 at 03:54:20PM +0000, Pavel via Digitalmars-d-learn wrote:
[...]
 Guess what, here's a new snippet:
 
 import std.stdio;
 import std.json;
 
 void main() {
   scope(failure) writeln("FaILED!!");
   string jsonStr = `{ "name": "1", "type": "r" }`;
   auto parsed = parseJSON(jsonStr).object;
   writeln("fail" in parsed);
 }
 
 Output is:
 null
 
 WAT?!
 
 Ofcourse, writing like:
 
 writeln(cast(bool)("fail" in parsed));
 
 Produces "false"... but why on earth boolean expression would output null?
It's not a boolean expression. The 'in' operator returns a pointer. Rationale: avoid double lookups, for example: if (auto ptr = "key" in assocArray) { doSomething(*ptr); } T -- The right half of the brain controls the left half of the body. This means that only left-handed people are in their right mind. -- Manoj Srivastava
Jul 24 2014
parent "Pavel" <nomail noplace.org> writes:
On Thursday, 24 July 2014 at 16:02:12 UTC, H. S. Teoh via 
Digitalmars-d-learn wrote:
 On Thu, Jul 24, 2014 at 03:54:20PM +0000, Pavel via 
 Digitalmars-d-learn wrote:
 [...]
 Guess what, here's a new snippet:
 
 import std.stdio;
 import std.json;
 
 void main() {
   scope(failure) writeln("FaILED!!");
   string jsonStr = `{ "name": "1", "type": "r" }`;
   auto parsed = parseJSON(jsonStr).object;
   writeln("fail" in parsed);
 }
 
 Output is:
 null
 
 WAT?!
 
 Ofcourse, writing like:
 
 writeln(cast(bool)("fail" in parsed));
 
 Produces "false"... but why on earth boolean expression would 
 output null?
It's not a boolean expression. The 'in' operator returns a pointer. Rationale: avoid double lookups, for example: if (auto ptr = "key" in assocArray) { doSomething(*ptr); } T
Thanks once again. Now I finally get this thing done with code like this: import std.stdio; import std.json; void main() { scope(failure) writeln("Failure!!"); string jsonStr = `{ "name": "1", "type": "r" }`; auto parsed = parseJSON(jsonStr).object; auto found = "fail" in parsed; if (found !is null) { string s = found.str; writeln(s); } else { writeln("No such key"); } } Still focus on wrapper class discussion :)
Jul 24 2014
prev sibling parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Thursday, 24 July 2014 at 15:54:21 UTC, Pavel wrote:
 On Thursday, 24 July 2014 at 15:48:32 UTC, Edwin van Leeuwen 
 wrote:
 On Thursday, 24 July 2014 at 15:42:58 UTC, Pavel wrote:
 On Thursday, 24 July 2014 at 15:38:06 UTC, John Colvin wrote:
 On Thursday, 24 July 2014 at 15:32:29 UTC, John Colvin wrote:
 On Thursday, 24 July 2014 at 15:15:37 UTC, Pavel wrote:
 Ok, let me start with the sample code:

 import std.stdio;
 import std.json;

 void main() {
 scope(failure) writeln("FaILED!!");
 string jsonStr = `{ "name": "1", "type": "r" }`;
 auto parsed = parseJSON(jsonStr);
 string s = parsed["fail"].str;
 writeln(s == "");
 writeln(s is null);
 writeln(s);
 }

 Running "rdmd app.d" doesn't produce any output.
 Can anyone explain such a behavior???


 PS: Running dmd v2.065 on Linux x64.
It's a bug in std.json (you should get a segfault, not no output at all) It is fixed now and I'm pretty sure it will be in 2.066 std.json has been improved a lot, but I would still recommend using http://vibed.org/api/vibe.data.json/ instead
perhaps "bug" is too strong a word, but it was a deficiency that is now corrected. You will get an exception thrown now and everything should work how you expect.
Maybe. But still it's not the way I expect, any time you check for non-existing property you must consider exception, which is very heavy to deal with in such a situation. I'd rather expect to get null, whenever I try to fetch non-existing property, and not an exception.
You can turn your json object into an AA object and then use in to check for existence (I know it is not very intuitive): JSONValue[string] jsonAA = parsed.object; if ( "fail" in jsonAA ) s = jsonAA["fail"].str;
 That's purely my point, and I don't claim to be right in this 
 way. It's up to Phobos maintainers to decide how to reprent 
 JSON parsing results.
Guess what, here's a new snippet: import std.stdio; import std.json; void main() { scope(failure) writeln("FaILED!!"); string jsonStr = `{ "name": "1", "type": "r" }`; auto parsed = parseJSON(jsonStr).object; writeln("fail" in parsed); } Output is: null WAT?! Ofcourse, writing like: writeln(cast(bool)("fail" in parsed)); Produces "false"... but why on earth boolean expression would output null? PS: Sorry, for such an emotional boom, I'm so frustrated right now.
The in operator in d returns a pointer to the element found or null. This might be a little confusing at first* but it makes sense for efficiency reasons. There is often a lot overlap between the work needed to test for presence and the work needed to fetch an element. For types where fetching elements is a significant extra cost you can always define a `bool contains(K key) { /* ... */ }` so a user can avoid this cost when appropriate. *although to be honest it's just a different reading: `b in c` can be read as "the b in c" or "is b in c?"
Jul 24 2014
prev sibling parent "Pavel" <nomail noplace.org> writes:
On Thursday, 24 July 2014 at 15:32:29 UTC, John Colvin wrote:
 On Thursday, 24 July 2014 at 15:15:37 UTC, Pavel wrote:
 Ok, let me start with the sample code:

 import std.stdio;
 import std.json;

 void main() {
  scope(failure) writeln("FaILED!!");
  string jsonStr = `{ "name": "1", "type": "r" }`;
  auto parsed = parseJSON(jsonStr);
  string s = parsed["fail"].str;
  writeln(s == "");
  writeln(s is null);
  writeln(s);
 }

 Running "rdmd app.d" doesn't produce any output.
 Can anyone explain such a behavior???


 PS: Running dmd v2.065 on Linux x64.
It's a bug in std.json (you should get a segfault, not no output at all) It is fixed now and I'm pretty sure it will be in 2.066 std.json has been improved a lot, but I would still recommend using http://vibed.org/api/vibe.data.json/ instead
I'm pretty sure it's improving, but it has that "Java" disease, which is creating new Types, which are just wrappers for common types. Why don't just use Variant[string] for objects, and Variant[] for arrays. This way you won't be putting another layer of knowledge for those who work with std.json.
Jul 24 2014