July 24, 2014
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
July 24, 2014
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?
July 24, 2014
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 :)
July 24, 2014
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.
July 24, 2014
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?"
July 24, 2014
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/
July 24, 2014
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...
July 24, 2014
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
July 24, 2014
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".
July 24, 2014
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.