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).