It’s defined via the value
in that expression, which would be more clear perhaps without the parenthesis:
with(
non_nil value <- :bloop,
do: value
)
And yet it is not? You can define a value just fine via a macro and indeed that is done in many cases in many libraries. As well as you didn’t have to specify a value to bind to, with my above macro you could just as well do:
with(
value = non_nil() <- :bloop,
do: value
)
That is why I often have default values in my macro’s for such bindings, so either method works just fine.
They work just fine if the macro is written to only return guard-safe calls:
iex(1)> defmodule MyMacros do
...(1)> defmacro is_not_nil(value), do: quote(do: not is_nil(unquote(value)))
...(1)> end
{:module, MyMacros,
<<70, 79, 82, 49, 0, 0, 4, 200, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 150,
0, 0, 0, 15, 15, 69, 108, 105, 120, 105, 114, 46, 77, 121, 77, 97, 99, 114,
111, 115, 8, 95, 95, 105, 110, 102, 111, ...>>, {:is_not_nil, 1}}
iex(2)> import MyMacros
MyMacros
iex(3)> defmodule Bloop do
...(3)> def my_func(x) when is_not_nil(x), do: x
...(3)> end
{:module, Bloop,
<<70, 79, 82, 49, 0, 0, 4, 100, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 131,
0, 0, 0, 14, 12, 69, 108, 105, 120, 105, 114, 46, 66, 108, 111, 111, 112, 8,
95, 95, 105, 110, 102, 111, 95, 95, 7, ...>>, {:my_func, 1}}
iex(4)> Bloop.my_func(42)
42
Actually it is on purpose that they don’t support macro’s in those positions, so sadly it won’t be fixed. However, you can of course make your own library to replace those functions with ones better suited for your purpose. ^.^
I’m actually a fan of having a macro that operates on an entire defmodule
declaration to mutate it en-masse to ‘fix-up’ inconsistencies like that (among other things).