The renderer guide's JSON Pointer Implementation Rules specifies the following:
Undefined Handling: Setting an object key to undefined removes the key. Setting an array index to undefined preserves length but empties the index (sparse array).
@gspencergoog posed some good questions while reviewng a downstream PR implementing this behavior (flutter/genui#938):
When are the nulls in lists cleaned up? And how are they handled when rendering? Wouldn't you expect the list to change size if you remove an entry?
The current semantics are a bit difficult for non-JS renderers. JSON has no undefined, JSON arrays have no sparse slots, and many implementation languages do not natively represent array holes. In Dart, for example, a renderer must either invent hole marker or collapse the hole to null. Collapsing tonull is lossy because null can also be an intentional list value.
This also means the protocol can create a state that it cannot faithfully serialize as JSON. If a client has [a, <hole>, c], what should it send back? [a, null, c] changes the meaning.
As far as I can tell, once a list accumulates holes, the only protocol-level way for the server to compact it is to overwrite the entire list.
Suggestion
Define deletion of an array index as a compacting remove/splice operation. For example, deleting /items/1 from [a, b, c] should produce [a, c].
The main downside is index shifting. After removing /items/1, what was previously /items/2 becomes /items/1. The spec should therefore also state that implementations must notify/rebind the parent list and affected descendant paths, not only the deleted path.
Other alternatives:
- Keep sparse semantics, but explicitly define a protocol-level representation for holes that is distinct from
null, including how that state is serialized.
- Add separate operations for "clear this slot" and "remove this item".
P.S.: somewhat related: #1499
The renderer guide's JSON Pointer Implementation Rules specifies the following:
@gspencergoog posed some good questions while reviewng a downstream PR implementing this behavior (flutter/genui#938):
The current semantics are a bit difficult for non-JS renderers. JSON has no
undefined, JSON arrays have no sparse slots, and many implementation languages do not natively represent array holes. In Dart, for example, a renderer must either invent hole marker or collapse the hole tonull. Collapsing tonullis lossy becausenullcan also be an intentional list value.This also means the protocol can create a state that it cannot faithfully serialize as JSON. If a client has
[a, <hole>, c], what should it send back?[a, null, c]changes the meaning.As far as I can tell, once a list accumulates holes, the only protocol-level way for the server to compact it is to overwrite the entire list.
Suggestion
Define deletion of an array index as a compacting remove/splice operation. For example, deleting
/items/1from[a, b, c]should produce[a, c].The main downside is index shifting. After removing
/items/1, what was previously/items/2becomes/items/1. The spec should therefore also state that implementations must notify/rebind the parent list and affected descendant paths, not only the deleted path.Other alternatives:
null, including how that state is serialized.P.S.: somewhat related: #1499