I don’t see the struct adding any value in this case; a plain map would serve the same purpose but save editing one place when adding a new value to collect.
A good way to spot this is that both reading or writing of the counts uses map operations ([] and Map.update) versus compile-time references like .some_field.
I’d recommend a list of two-element tuples for Parser’s translations:
@moduledoc false
defp translations do
[
{"Example String 1", :foo],
{"Example String 2", :bar],
# Some complex strings that optionally may need to be further parsed with regexps, etc., hence bigger tuples
# {~r/some weird thing/, extra_args, :baz}
]
end
This ensures that functions like Enum.find_value(translations(), ...) always check to see if they match in the same order, ensuring that overlapping definitions like:
{"Example String", :short_foo],
{"Example String 1", :foo],
always give the same result.
Stringifier has a similar-but different list just like in your already-posted code, which is slightly easier to write since the first element of all the tuples is an atom.
Again the list ensures that the result iterates over the keys in the correct (& consistent) order.
One place to NOT use a list is for keeping the counts! For instance:
# CAUTION: PERFORMANCE HAZARD BELOW
"large_text_file.txt"
|> File.stream!()
|> Enum.reduce([total: 0], fn line, acc ->
tl = find_tl(line)
acc
|> Keyword.update(:total, 1, &(&1+1))
|> Keyword.update(tl, 1, &(&1+1))
end)
Unlike in the previous cases, the key order of the result isn’t something we care about - and maintaining it means that Keyword.update is slower than Map.update by a factor roughly the size of acc. This kind of random access is a good indicator that a map is the right choice.
This still leaves two places that need editing when adding a new value to be counted, but IMO that’s not unreasonable:
- one place says “this is how to collect this count”
- the other place says “this is how to display this count”
Fusing the two together into one list would force one of the orderings discussed above to match the other; either the display order would need to exactly follow the matching order, or the other way around.


















