You mostly seemed unaware of the easy workaround to avoid unnecessary object construction. Your second criticism is more valid. While not logically required without extra space as you say, it is _often_ easy to tell a default value from a later value. So, I think `mgetOrPut` covers a very large fraction of use cases. But not all.
Non-inlined functions can also take more time than the whole lookup process for integer keys in L1 cache tables. { Not necessary, but a potential hazard. } In my home grown C libraries I just do `if (cell=find(t, key, &insertSpot)) cnt++; else { cell = preIni(&t, key, insertSpot); cell->cnt=1; }` with less expert all-in-one put/get/set-type interfaces. The expert interface has no problem of any kind except that you need to know more to use it. A safer way to go in Nim might be like `template withValue[A, B](t: var Table[A, B]` maybe called `template updateOrInit` or `withInit`, but where the 2nd clause lets you init a just allocated value. That'd avoid tricky `var` passing conventions, the need to define `let` or `const` objects, **_or_** worry about if people's functions get inlined, _but_ introduce template conventions which may be viewed as "more tricky". I think I would personally prefer that 2-body template, but I may be weird. Beats me what would be most popular, risky, or even which is "simplest". I always think "Big Tent"/"all of the above". If it was up to me I'd say both your callback proc and the template, but then people complain about too large APIs or ask for new things without fully understanding existing stuff. (That is **_not_** intended as a jab at you..partial learning just tracks big APIs and people already complain Table is too big.) Anyway, you should open some PR and see what Araq says. He gives far more attention to concrete code additions than forum theorizing.