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

wojtekmach
Hey everyone! Req is an HTTP client for Elixir that I’ve been working on for quite some time. There is already a lot of HTTP clients out...
New
handnot2
Samly can be used to enable SAML 2.0 Single Sign On in a Plug/Phoenix application. This library uses Erlang esaml to provide plug enabl...
New
woylie
Flop is an Elixir library that applies filtering, ordering and pagination parameters to your Ecto queries. offset-based pagination with...
New
restlessronin
The repo is at GitHub - cyberchitta/openai_ex: Community maintained Elixir library for OpenAI API · GitHub. Docs are at OpenaiEx User Gu...
152 11030 135
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
fuelen
Hi all! I want to present a small library which provides a mix task for generating an Entity-Relationship Diagram for Ecto schemas. You...
New
woylie
Phoenix components for pagination, sortable tables and filter forms with Flop and (optionally) Ecto. pagination cursor pagination sorta...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
mudasobwa
I am seeing a lot of aplications of Argumentum ad Vericundiam in software discussions. They do link some piece of writing and point us to...
New
bartblast
Hey folks, I just published a post about Hologram’s funding and where the project goes next - the short version: Curiosum as Main Spons...
New
sorenone
Today we’re releasing Oban for Python. Not an Oban client in Python. Not a pythonx wrapper embedded in Elixir. Nope, it’s a fully operati...
New
Herve37
We’re evaluating API mocking tools for OpenAPI-based projects and would love to hear what other teams are using. We’re particularly inte...
New
AstonJ
This showed up on my feed.. anyone heard of it? Just hype? Ox Alpha is a reasoning model designed for coding, sustained ag...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews