I'd still go with the one @shirleyquirk posted. That version will only do it for tables, and not arbitrary values, saving you from the issue that the C++ code had. Compare this: proc `[]`[A, B, C](t: var Table[A, Table[B, C]], key: A): var Table[B, C] = t.mgetOrPut(key, initTable[B, C]()) var nested: Table[string, Table[string, Table[string, int]]] nested["this"]["works"]["fine"] = 42 #echo nested["this"]["doesn't"]["work"] # Will throw an exception about the key not being found Run
To this, which has similar behaviour to the C++ version which silently inserts keys: var nested: Table[string, Table[string, Table[string, int]]] nested["this"]["works"]["fine"] = 42 discard nested["now"]["this"]["works"] # Adds a default int to the key echo nested["now"]["this"].len # Now there is something in the "this" table echo nested["now"]["this"].hasKey("works") # And the works key have been silenly added echo nested["now"]["this"]["works"] # With the default value of an int, which is 0 Run The first version will still shadow-add table entries to the subtables if you do something like `echo nested["a"]["couple"]["keys"]`, but you could always also create a procedure like: proc hasKey[A, B, C](t: Table[A, Table[B, C], k: A): bool = t.hasKey(k) and t[k].len != 0 Run To make `hasKey` behave a bit more like "has key with useful data".