Comments to the JSON related proposals
zeniko at gmail.com
Sat Aug 18 16:39:13 PDT 2007
Brendan asked me to comment on the proposals at  after having seen
that I had implemented several aspects slightly differently for Firefox'
Session Restore functionality (which offers a JSON-based API ). This
platform until the JSON proposal is finalized and natively implemented .
JSON was a nice fit for our API as we internally use an object tree to
store the various information related to all open windows. For
efficiency and simplicity reasons, we do however store certain
non-serializable objects in that tree as well which required us to
implement a filter on toJSONString (see comments #1 and #2 below).
With the code being added to the Mozilla platform, I made some
additional changes to make it IMO slightly less fragile to use - that's
comments #3 and #4. The other two comments #5 and #6 are unrelated
suggestions which we haven't implemented ourselves yet.
My 6 modification suggestions are:
1. toJSONString needs an optional filter argument
This has already been discussed but apparently not made it into the
proposal itself. To reiterate the main reason: without a filter, an
object containing temporary/internal keys has to be duplicated first
before it can be encoded - and duplicating it or JSON encoding it
yourself will of about the same complexity, so you lose the convenience
of either being able to add internal keys or of using toJSONString.
2. The optional filter argument should allow both function and blacklist
This shouldn't be an either/or choice, as there are several use cases
where a filter might be used which have quite different needs: in the
case of temporary/internal keys scattered in an object, it might be
easier to just specify those keys and be done with it - whereas if you
want to ensure a contract (and thus prefer a whitelist), you'll need a
way to consider a key's context which you can only do in a function
anyway (unless you want to introduce XPath4JSON).
In the first case you furthermore most probably use less temporary keys
than actually relevant ones which makes the blacklist both
smaller/better to oversee and speedier than a whitelist.
3. |undefined|, functions, etc. should not be silently dropped
Since JSON is a serialization format, encoding and decoding should be
fully reversible - or else you risk running into unexpected subtle
errors which make JSON related code more fragile than necessary.
Should objects to be serialized for some reason contain functions, they
should rather be blacklisted so that it is explicit what will be dropped.
|undefined| OTOH mostly appears in sparse Arrays which don't exist in
many other languages and which you thus shouldn't be using for
interoperability's sake, anyway. If you however depend on sparse Arrays
(i.e. if you couldn't for clarity rewrite your code to use dense
Arrays), you again risk subtle errors if you're not aware that you won't
get them back as you might expect.
Only possible exception to this rule: dropping |undefined| at the very
end of an Array for the use case where you preallocate an Array larger
than you need for efficiency reasons.
4. Date should not be serializable
Same reason as above: as long as it's not unambiguously deserializable,
serializing it leads to unnecessary fragility. Having instead a filter
function on toJSONString analogous to parseJSON's would nicely restore
the balance for easy-to-read encoding/decoding.
5. Pretty printing shouldn't default to 4 spaces
Indentation is always a matter of taste and should thus not default
unchangeably to an arbitrary value. Two better options: either indent
with a single tab (which can then easily be replaced with as many spaces
as you like as there won't be any other unencoded tabs in the returned
string); or accept an integer value as argument indicating how to indent
where non-negative numbers mean spaces and negative numbers mean to use
as many tabs for indentation.
6. Filter functions should be able to delete keys by returning |undefined|
|undefined| is an illegal JSON value and can thus be used safely for
this purpose, allowing you to do completely without Array.filter or
similar both for encoding and decoding. This would mostly be used for
encoding where with a filter function you can choose yourself to
implement a whitelist (or an extended blacklist).
Criticism and comments are welcome. In case any of those arguments has
already been brought forward, please kindly ignore them.
More information about the Es4-discuss