[Haskell-cafe] Ordered JSON objects?

Tobias Dammers tdammers at gmail.com
Tue Dec 16 09:10:21 UTC 2014

On Tue, Dec 16, 2014 at 08:43:08AM +0000, Michael Snoyman wrote:
> On Tue Dec 16 2014 at 10:39:32 AM Tobias Dammers <tdammers at gmail.com> wrote:
> > On Mon, Dec 15, 2014 at 11:01:12PM +0100, Wojtek Narczyński wrote:
> > > On 15.12.2014 20:32, Tobias Dammers wrote:
> > >
> > > >Anyway, one thing I'm running up against is that I am going to need
> > > >ordered key/value collections, which I believe is something JSON does
> > > >not support out-of-the-box: "objects" ({"foo":15, "bar":23}) are
> > > >conceptually unordered key/value collections (and Aeson treats them as
> > > >such, using hash maps as the intermediate storage format), so I lose
> > > >ordering;
> > >
> > > JSON does not forbid ordering of maps by key, I believe. But you'd need
> > to
> > > create an OrderedMap and patch aeson. It would be very useful, the
> > mixing of
> > > key order is nuisance for human JSON consumers.
> >
> > No, that's not what I meant. By "ordered", I meant that the in-memory
> > representation of the document should maintain file order. Aeson uses a
> > HashMap to store key/value objects, which is an unordered container;
> > what you suggest would be something like Map (storing elements by key
> > order), but what I'm talking about is more like [(Key, Value)], i.e.,
> > keeping file order intact.
> >
> >
> I think your best bet is to bite the bullet and just deal with an array,
> forgetting the object entirely (at least at the top level). Any time I've
> needed to implement some kind of ordered data in JSON, I've used an array.

Yes, that's what I was thinking myself. I absolutely don't want to use
"looks like JSON but isn't", I really want to stick with standard JSON,
for so many reasons.

My tentative design so far is to use an array of "anything"; each
element can be a scalar (which generates an unnamed field), an object
with the magic properties "_name" and "_value", which generates a named
field, or something else, which generates an unnamed field containing
that something else.

So I'd have this:

    [ "foobar"
    , { "baz": "quux", "boink": "blip" }
    , { "_name": "foobar", "_value": "oink" }
    , { "_name": "quuux", "_value": { "apples": "oranges" } }

...which would map to something like (in pseudo-Show notation):

    [ ("_field_1", String "foobar")
    , ("_field_2", Object (fromList [ ("baz", "quux"), ("boink", "blip") ]))
    , ("foobar", String "boink")
    , ("quuux", Object (fromList [ ("apples": "oranges") ]))

This would meet the requirement of providing ordered properties, and it
would allow for arbitrary JSON (i.e., the mapping would be total over
all valid JSON arrays); the downside is that the ToJSON and FromJSON
instances for my Record type would be a bit more complex than what I
have now, but I guess that would be OK. Another downside would be that
if an element specifies both "_value" *and* non-magic fields, I would
have to decide whether I want to treat "_value" as non-magic, or throw
away the non-magical fields.

More information about the Haskell-Cafe mailing list