Question about dictionaries and their nuances

One gotcha I’ve found is performance (which is mentioned in the documentation) – dicts aren’t a replacement for library(assoc) or library(rbtrees). I have some code that does a big update on dicts (I’ll eventually get rid of this dict and replace it by rbtree):

%! update_new_dict(+KVs:list(pair), -Dict0:dict, +Dict:dict) is det.                                                    %% Add all key-value pairs in KVs into the dict, skipping any that
%% are already in the dict.
%% The keys are processed in order, so if a key is added, any subsequent
%% values of that key are ignored.
%% Note that dict_pairs(Dict, Tag, KVs) doesn't allow duplicate keys.

%% This is the straightforward implementation, but it creates
%% a lot of garbage and is slow.

%% update_new_dict([], Dict, Dict).
%% update_new_dict([K-V|KVs], Dict0, Dict) :-
%%     (  get_dict(K, Dict0, _)
%%     -> Dict1 = Dict0
%%     ;  put_dict(K, Dict0, V, Dict1)
%%     ),
%%     update_new_dict(KVs, Dict1, Dict).

%% The following is several times faster than the above.  (For 11,000
%% items, make_rb is about 20x faster than the equivalent loop for a
%% dict, but there's still significant cost converting to/from rbtree).
%% It would be better to just leave everything as a RB-tree.

update_new_dict(KVs, Dict0, Dict) :-
    dict_pairs(Dict0, Tag, KVs0),
    ord_list_to_rbtree(KVs0, Rb0),
    make_rb(KVs, Rb0, Rb1),
    rb_visit(Rb1, KVs1),
    dict_pairs(Dict, Tag, KVs1).

make_rb([], Rb, Rb).
make_rb([K-V|KVs], Rb0, Rb) :-
    rb_insert(Rb0, K, V, Rb1),
    make_rb(KVs, Rb1, Rb).