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

restlessronin
The repo is at GitHub - cyberchitta/openai_ex: Community maintained Elixir library for OpenAI API · GitHub. Docs are at OpenaiEx User Gu...
152 12366 136
New
type1fool
WebAuthnLiveComponent WebAuthnComponents See this post about renaming the package. Passwordless authentication for Phoenix LiveView app...
New
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
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
kip
In 2021 I started a new library called Tempo with the objective of modelling time as a set of intervals - not as instants. In 2022 I gave...
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

Other Trending Topics Top

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
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
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
Null-logic-0
What IDE or editor are you using for Elixir development? Personally, I use Zed, and I really like it, but sometimes I wish there were a ...
New
alexslade
Fly’s CEO posted this recently - Turn And Face The Strange · The Fly Blog It says that Fly is going all-in on sprites, which is a worry ...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews