Qqwy

Qqwy

TypeCheck Core Team

Hello everyone,

I wrote a small library today called MapDiff.
It returns a map listing the (smallest amount of) changes to get from map_a to map_b:

iex> foo = %{a: 1, b: 2, c: %{d: 3, e: 4, f: 5}}
iex> bar = %{a: 1, b: 42, c: %{d: %{something_else: "entirely"}, f: 10}}
iex> MapDiff.diff(foo, bar)
%{changed: :map_change,
  value: %{a: %{changed: :equal, value: 1},
    b: %{added: 42, changed: :primitive_change, removed: 2},
    c: %{changed: :map_change,
      value: %{d: %{added: %{something_else: "entirely"},
      changed: :primitive_change, removed: 3},
    e: %{changed: :removed, value: 4},
    f: %{added: 10, changed: :primitive_change, removed: 5}}}}}

This is mainly useful if you have two maps describing the state of something, where
replacing all of the old state and then filling in the new is too slow, which means that only
replacing the things that actually are changed is better.

It is similar to what Elm does to represent its output to the HTML Domain Object Model. The reason I wrote MapDiff is that I am planning on writing a library that wraps Erlang’s wxWidgets bindings in a similar way that Elm wraps the HTML DOM, which would allow people to write GUIs in a Functional style (wxWidgets itself is Object-Oriented). Does this sound like a huge undertaking? Yes! Let’s see how far I can get with it :grin:…


Anyhow, MapDiff is a very small and basic library, but it might be useful for some other people as well, so I thought I’d publish it on Hex.pm :slight_smile: . Feedback is of course greatly appreciated.

Showing Posts 1 to 10

sashaafm

sashaafm

That seems like a useful simple library! Good job @Qqwy!

OvermindDL1

OvermindDL1

That would be awesome and is entirely possible! I’d thought about it myself but wrapping to a QT layer instead. ^.^

This library will be useful to me though, I already have my more specialized one currently. :slight_smile:

Qqwy

Qqwy OP

TypeCheck Core Team

Hey @OvermindDL1! Please do tell me more about your ‘more specialized one’. And also, I’m of course going to try to keep the Functional Reactive Programming layer as separate as possible from the WxWidgets layer, so hopefully it will be possible to swap one rendering backend for another.

But this is all still completely theoretical right now, of course :grin:.

OvermindDL1

OvermindDL1

Mine just converted atoms to binaries if it compared an atom and binary, just an ease of use thing and I can always convert it before of course. ^.^

Qqwy

Qqwy OP

TypeCheck Core Team

All right! MapDiff is updated to 1.1.0.
The single but important new feature: Supporting structs in a meaningful way.

  • comparing two structs of the same type returns a map of fields that were changed.
  • comparing two structs of a different type returns a primitive_change where the whole of the old struct was replaced for the whole of the new struct.

Examples:

iex> MapDiff.diff(%Foo{}, %Foo{a: 3})
%{changed: :map_change, struct_name: Foo,
  value: %{a: %{added: 3, changed: :primitive_change, removed: 1},
    b: %{changed: :equal, value: 2}, c: %{changed: :equal, value: 3}}}

When comparing two different kinds of structs, this of course results in a :primitive_change, as they are simply considered primitive data types:

iex> MapDiff.diff(%Foo{}, %Bar{})
%{added: %Bar{a: "foo", b: "bar", z: "baz"}, changed: :primitive_change,
  removed: %Foo{a: 1, b: 2, c: 3}}
Qqwy

Qqwy OP

TypeCheck Core Team

By the way,

The library consists of one small module (or actually, one single public function, even).

The code still uses quite a few if/else statements inside this function definition. Is there a way to make this code even more Elixir-idiomatic?

bbense

bbense

Short circuit the equal case maybe ?

iex(1)> foo = %{ :a => 1, :b => 2 }
%{a: 1, b: 2}
iex(2)> bar = %{ :a => 1, :b => 2 }
%{a: 1, b: 2}
iex(3)> foo == bar
true

bbense

bbense

Another way to go would be to create a Diff protocol and recursive apply the protocol in it’s implementation.

andre1sk

andre1sk

It’s possible to do same things with functions and pattern matches something like
https://github.com/andre1sk/elixir_map_diff/blob/refactor/lib/map_diff.ex

Qqwy

Qqwy OP

TypeCheck Core Team

The equal case is already short-cirquiting, see line 139.

I thought about this, but decided against it, as I believe that the current implementation is the only one that makes sense (different types of structs → primitive change, same types of structs → recurse over struct keys).

This is absolutely amazing. I had no idea that it was possible to refactor it so beautifully :heart_eyes: . Please do open Pull Request, so I can put these changes in and give you credit!

Where Next? Top

Trending in Announcing Top

mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
kip
Localize is the next generation localisation library for Elixir. Think of it as ex_cldr version 3.0. The first version will be released ...
New
quatermain
Hello, I’m sharing my plugin here in forum after some time so it has time to mature and proof yourself. I use Claude Code daily on a pr...
New
gtcode
Aloha gang, There’s a new class of AI model out from TypeSafe. Jev is their flagship model. You can learn about it here: ...
New
LostKobrakai
I’ve recently created a small library phoenix_vite integrating the vite build tooling with phoenix. It provides an igniter.installer t...
New
danschultzer
I needed something like premailer for rails, and after searching, I decided to make an easy-to-use library to handle inline styles and co...
New
kraleppa
If you’ve ever had to debug a BEAM node you know it can be a painful process. Parsing raw data, or dealing with clutter often gets in the...
New

Other Trending Topics Top

dominicletz
Hey there, I haven’t seen a list of useful Elixir specific skills for the popular AI tools yet so I’m starting one here with my first. ...
New
raa-ziq
Hi everyone :waving_hand: I wanted to share something I’ve been building — NowBlind, a random chat app designed to help people discover ...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
OndrejValenta
(I just needed to vent somewhere and LinkedIn is full of hope, or hype, I’m not sure which exactly) AI dream has many faces, but general...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New
AstonJ
AI tools and services seem to be the new JS framework - with new ones popping up every 5 minutes - hence it might be worth posting one of...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews