google/jsonnet

Feature: Convert while preserving the order of fields in objects

eteichm opened this issue · 13 comments

I suggest to add the feature of preserving the order of list items when converting to json, maybe as an option. If available, please add it to the manual.

Order of list elements is always preserved. Do you mean the order of object fields?

Yes, I meant preserving the order of object fields. Currently, they seem to be sorted in alphabetical order.

There are some existing issues about that (#407, probably something on go-jsonnet side as well...). There are some good reasons not to do it (it shouldn't matter, JSON objects are unordered), but it could be a usability win. So, if someone can propose a good, coherent solution I'll be happy to help make it happen.

It's not exactly clear how to handle this in all cases. There were some discussions in the mailing list about that as well.

Closing this for now and re-opening the original issue (where we have more context).

My 2c is that not sorting the keys would also interfere with content hashing use-case e.g. doing std.md5(std.toString(obj)).

@ilya-kolpakov Yes, that is correct. We certainly want to keep backwards compatibility w.r.t. how objects are manifested. So probably some additional hidden parameter on an object would be necessary to have fields manifested in non-alphabetical order.

Hi @sbarzowski is there any update on this?

@arpitjasa-db Not really. You can take a look at the mailing list for the related discussion.

If someone can come up with an acceptable proposal and wants to implement it, I'll be happy to support it.

I have experimented with this feature in my Rust implementation of Jsonnet, what do you folks think about this?
https://github.com/CertainLach/jrsonnet/releases/tag/v0.5.0-pre1-test

Nice! Some questions:

  • This is deep, right? I.e. preserve_order applies to nested object as well, right?
  • What exactly happens to the order of elements with +? Do you always put the overridden fields after the untouched ones?
  • How does it work with object comprehensions?

If we can agree on semantics I'm happy to upstream this (unless @sparkprime protests).

Yep, serialization order is applied deeply
I can't think of any case, where mixed ordering would be useful

I always put overriden fields after untouched, however i think + should keep old ordering of original field, i will change that

In object comprehensions fields are ordered by insertion, i.e {[k]: 1 for k in ['b', 'a', 'c']} will have b, a, c ordering

I always put overriden fields after untouched, however i think + should keep old ordering of original field, i will change that

Yeah. I expect the most common case would be to have a big object with fields in expected order and then override some of them. It would be annoying if this would always put them in the end.

In object comprehensions fields are ordered by insertion, i.e {[k]: 1 for k in ['b', 'a', 'c']} will have b, a, c ordering

Sounds reasonable.

I have played with this feature couple of days, and i think about this as better behavior:

Both overrides and + should keep position of original field declaration:

{a: 1, b: 2} + {c: 4, a: 2, b+: 1}
// =>
{a: 2, b: 3, c: 4}

Originally i was resetting position of overriden field to have better understanding for where this field was defined, but this breaks cases like

{apiVersion: error "missing api version", kind: error "missing kind"} + {kind: 'Pod', apiVersion: 'v1'}

For my usecase i should better think about something like manifestDebug, which will yield something like

{apiVersion: <overriden>, kind: <overriden>} + {kind: 'Pod', apiVersion: 'v1'}

Agreed. I like your approach and would be happy to make it official.

manifestDebug

This technically breaks some laws that + on object is supposed to follow (e.g. exposes internal structure of the object to the user, so you can no longer override everything completely). I understand this is intended just as a debugging feature, but it's not something I would like to have upstream :-).