jsonpp
jsonpp copied to clipboard
Behaviour of operator[] is unintuitive
Currently, you return an rvalue from operator[], not an lvalue. Furthermore, operator= is not banned on rvalues as it should be. This leads to the exceedingly unintuitive behaviour where
json::value v;
v["thing"] = "string";
does not actually modify v at all, but silently leaves it unchanged.
I think that either supporting this use of operator[], or making it a compiler error, would be useful.
From the code, a temporary empty object is returned if the lookup fails: e.g. it constructs an rvalue like you said. The code already performs checks and returns the bogus value if it can't find it. This can't be turned into a compiler error because it's a run-time decision: for example, the following code does what you think it should:
json::value v(json::object{ {"thing", "woof"} });
v["thing"] = "string";
For ease of use with the code @DeadMG posted, my suggestion would be:
- if the
json::valueis null, turn it into anjson::objectand then populate the object with"thing" : "string"(or whatever the desired value is). - If it is non-null and an object, insert/replace the value of "string" for key "thing"
- If it is non-null and not an object, it should throw (instead of returning a useless value), as you can't index into a not-object
Most of these checks are already done by the code, this just makes the default behavior more user-friendly and clearly notifies the user with an error if they are doing the wrong thing™ (I am not sure how acceptable runtime errors and throwing are).
Implementation that would make operator[] behave 'intuitively': https://github.com/ThePhD/jsonpp/commit/a1be7f6d3c742173793e0a183d5deb2d9a7f1556
This can't be turned into a compiler error because it's a run-time decision
Assigning to an rvalue is not a run-time decision, it's a compile-time one and one that ref-qualifiers were made for. It would ban all uses of obj["thing"] = "string", which would fix the problem of the silent unintuitive behaviour.
But obj["thing"] = "string" works when obj is actually a json::object and has the key (as outlined above). The only time it doesn't work is when obj is not an object or does not have the key: in both cases, you're assigning to an r-value, but in only one case it works. That is the exact definition of a runtime decision.
It doesn't work in the slightest. operator[] always returns an rvalue, assignment to which is worthless. The value category of the expression cannot change depending on the run-time situation of the object.