Released: deep_merge 0.1.0 for Elixir

As you might have seen on this blog or on twitter I’m thoroughly enjoying elixir. One thing that I found to be thoroughly missing is deep_merge – given two maps merge them together and if a merge conflict occurs but both values are maps go on and recursively merge them as well. In Ruby it is provided by ActiveSupport – you don’t need it THAT often but when you need it, it’s really great to have. The most common use case for me is merging a user specified configuration with some sort of default configuration to get the final configuration.

So at first no one else seemed to have the need for deep_merge, strange huh? About 1.5 months later it seemed others were having the same problem/question as in this stackoverflow question or the gist linked here:

So others do want it! Time to propose it to the elixir-core mailing list! Lots of people seemed to like the idea and were in favor of it, none of the core team members though and the discussion soon went on to be a bit more about implementation details. So, after some time I went and thought “might as well draft up an implementation in a PR so we can discuss this” – and so it was.

As you might have guessed from the blog post title, this PR didn’t get through as the core team thought it was a bit too specific of a use case, the implementation had its flaws (not handling structs properly – I learned something!) and it wasn’t general enough as it didn’t handle keyword lists. During the discussion José also mentioned that using protocols might be the way to go.

Using protocols seems to be the most correct but it feels a very niche feature to justify adding a new protocol to the language.

While I’d have liked to see it in Elixir core I gotta commend the elixir maintainers on rejecting features – I know it can sometimes be hard but in the end it’s for the better keeping the language focused and maintenance low. And one can always write a library so one can pick and choose to get the functionality in.

So what do you do? Well, implement it as a library of course! Meet deep_merge 0.1.0!


DeepMerge.deep_merge(%{a: 1, b: [x: 10, y: 9]}, %{b: [y: 20, z: 30], c: 4})
# => %{a: 1, b: [x: 10, y: 20, z: 30], c: 4}

view raw

deep_merge.exs

hosted with ❤ by GitHub

Why would you want to use deep_merge?

  • It handles both maps and keyword lists
  • It does not merge structs or maps with structs…
  • …but you can implement the simple DeepMerge.Resolver protocol for types/structs of your choice to also make them deep mergable
  • a deep_merge/3 variant that gets a function similar to Map.merge/3 to modify the merging behavior, for instance in case you don’t want keyword lists to be merged or you want all lists to be appended

All of these features – especially pit falls like the struct merging – are reasons why it might be profitable to adopt a library and not implement it yourself. So, go on check it out on github, hex and hexdocs.