correction to previous O definition
O =. 2 : 'm , ''_'' , (>n) , ''_'''~
> Since a dictionary is a locale, you could have 'nested' dictionaries by
using the locale#.
Possible for sure. references are fragile. references can be built from kv (must be to build object value references from scratch, as loading them from disk is fragile), and kv data structure built from references, but I feel user code always wants data instead of a references, and data is needed for serialization (disk and network)
my 2 big applications for dictionaries:
1. inverted tables where keys are field names is the core for generic table operations. field types can be inferred by first value, but an embedded dictionary with "magic key" TYPES (same keys as parent dictionary) could be used for "record" validation. The append as edit optional functionality is thread/locking friendly, and afaiu, the strategy used by nearly all RDBMSs. i: is used to retain unique access. Allowing duplicates also permits keyed multijoin operations.
In general, I believe delete operations are extremely rare, and temporal data (example current employee) can be a flag value, where you might still need person (former employee) data for other purposes (pension?). Setting (appending) a field value to a null code can be equivalent to delete. Having the database engine in user code allows functions that optimize down to engine level.
2. Towards a generic "windowed greed" search/optimization function build on chess positions, that include a lot of baggage properties (turn, enpassant, castling rights) and inverted table of moves, and scores that rank greediest alternative moves to explore. Scores are lazily created whole column when accessed, and an embedded dictionary is lazily created to create the new board from applying a move. A tree structure is created where thread friendliness is given by letting any 1 subthread have sole control over any board depth, and then updating score from parent thread (which also has sole control over top/its level board state. Serialization comes into play where evaluation at depth shows the score of a move so incredibly poor that it is unlikely to ever be probed again, and moving it to disk can free memory for more likely depth exploration. Dictionaries allow for "magic keys" that permit application categories (generic) in self contained datastructure, just because an application can walk down a tree structure through programming, doesn't mean that effortless serialization is not appreciated.
Because each dictionary is modestly small and under single thread control, updating dictionary in place saves space/consistency (even if depth moves dictionaries are returned and J is forced to manage drastically expanded size of parent key value). A serialization problem in this scenario is that the limit on number of files of OS can be reached if every depth is a single file.
I'd suggest the gold standard for dictionary representations would be a native J type (3!:1 support). This seems very close already since 16!: function family does all operations. However it is structured internally, if J builtin functions could see it as keys =: 0&{:: where dictvar (y argument) looks like an inverted table of keys ,&:< values ... would also be a gold standard.
As Jan-Peter suggested, inferred value types have advantages. One being a null code that can be part of a multiple put operation to "effectively signal deletion/uninitialization of key" to application code. While initial shapes can be marginally useful, it is more like an optional i.0 4, to signal a table shape that will be used to append to. It is only marginally useful because this structure can be set in initial key assignment, but that is useful in empty schema creation where constraints are set, and magic keys such as TYPES, INITIALSHAPES can provide the functionality instead. It seems extremely limited to have a value type and shape limited at dictionary creation, because values that are lists/tables of unknown length at creation time seem blocked, in addition to the "null code".
Limiting keys to numeric or symbol (boxed string equivalent) seems good enough. The example in nuvoc page is a unique to unique table where reverse lookup would be a major use.