Dark Kernel
Link here: GitHub - tmbb/elixir_dark_kernel: Elixir functions that use dark magic
(not available on hex yet)
A couple years ago Andrea Leopardi and Chris Meyer created some pretty cool libraries to add ES6-style shorthand maps. In elixir notation, one would be able to write somthing like %{a, b, c}
which would be equivalent to %{a: a, b: b, c: c}
. It turns out the libraries didnβt get much use. Iβve always thought that they were very intersting libraries and came up with the idea to extend those concepts to keyword lists.
This library is the result of those ideas. It is very simple, and it was coded in an afternoon, but I think it has some pretty cool capabilities. The library embeds the source of ShorterMaps, which I plan to extend in the near future. @OvermindDL1 might enjoy this.
Despite having named this library the βDark Kernelβ, I actually think it could be useful in real-world projects. It does have some βmagicβ (it calls Code.string_to_quoted!/1
at least once), but all (dark!) magic works at compile time, and the macroexpanded code is not that complex.
Dark keyword lists
Meet dark keyword lists, the simplest form:
import DarkKernel
opts = [a: 1, b: 2, c: 3]
# Pattern match the keyword list against an existing variable
~k[a, b, c, d = opts]
assert a == 1
assert b == 2
assert c == 3
assert d == nil
Dark keyword lists with constant defaults:
import DarkKernel
opts = [a: 1, b: 2]
# Pattern match the keyword list against an existing variable
~k[a, b, c: "a string", d: :an_atom, e: 42, f = opts]
assert a == 1
assert b == 2
assert c == "a string"
assert d == :an_atom
assert e == 42
assert f == nil
Dark keyword lists with defaults which are arbitrary expressions:
import DarkKernel
opts = [a: 1, b: 2]
# Pattern match the keyword list against an existing variable
~k[a, b, c: 1 + 2, d: :rand.uniform(), e: 3.14 + :rand.uniform() = opts]
assert a == 1
assert b == 2
assert c == 3
assert is_float(d)
assert is_float(e)
Instead of returning nil
for missing keys, we can raise an error. To do it, just prefix the required key with a bang (!):
iex(1)> import DarkKernel
DarkKernel
iex(2)> opts = [a: 1, b: 2, c: 3]
[a: 1, b: 2, c: 3]
# This will bind the variable to `nil`
iex(3)> ~k[a, b, x = opts]
[a: 1, b: 2, x: nil]
iex(4)> x
nil
# This will raise an error
iex(5)> ~k[a, b, !y = opts]
** (KeyError) key :y not found in: [a: 1, b: 2, c: 3]
(elixir 1.14.1) lib/keyword.ex:595: Keyword.fetch!/2
iex:5: (file)
iex(5)>
Dark maps
Dark maps are currently implemented using ShorterMaps. Due to dificulties of using a macro inside another macro, and because I wanted all sigils to be importable from the same module, dark_kernel
embeds the source code of ShorterMaps
.
In the (near) future, dark_kernel
will support more advanced pattern matching capabilities for dark maps, similar to the ones supported by dark keyword lists.
iex(1)> import DarkKernel
DarkKernel
iex(2)> ~M{a, b, c} = %{a: 1, b: 2, c: 3}
%{a: 1, b: 2, c: 3}
iex(3)> a
1
iex(4)> b
2
iex(5)> c
3
iex(6)>