Thanks for this; pretty much the response I was expecting but very well said.
My opinion is that functions that take quoted code do actually do the 99% job of macros pretty well. I also think creating completely new syntactic forms is fantastic for a solo project; but not so great when working in a team. So I'm left thinking what difference does it actually make. My general feeling is that I tend to write macros in Clojure just to deal with someone else's macros; i.e. macros 'layer' whereas functions compose.*
Incidentally, I've been curious about but never looked at Erlang's parse transforms because they have - in my mind at least - a big 'here be dragons' sign above them. Enough articles have warned me off to make me nervous. Would love to know more though.
Regarding your point about cleaning up other people's macros.
In Elixir macros are imported into local scope only when the user explicitly asks for it. Most libraries provide a `__using___` macro that can modify current scope.
For instance, `use ExUnit.Case` allows you to write tests like this
test "my test case" do
assert funcall() == "value"
end
instead of this
require ExUnit.Case
ExUnit.Case.test "my test case" do
ExUnit.Assertions.assert funcall() == "value"
end
So it basically imports a bunch of stuff for you, but only when you call `use ExUnit.Case`.
The consensus in the community right now is to not get carried away with macros and DSLs. Even if your library provides a DSL, it should be based on a functional API that is mostly usable without macros.
And lastly, remember that `use`, `require`, and `import` modify only the current lexical scope. I wrote this macro[1] that replaces the built-in `|>` operator with a version that prints its output to the console. You can `use PipeInspect` inside one function and only that function's body will get the overriden implementation of `|>`.
The consensus in the community right now is to not get carried away with macros and DSLs. Even if your library provides a DSL, it should be based on a functional API that is mostly usable without macros.
Yup. But what people say and what people do is often not the same thing :).
Sure. I just wanted to stress the point that macros are local in their scope. It's nothing like monkey-patching in Ruby where importing a module can change all divisions from floats to rational numbers.
Erlang parse transforms give you access to the full AST of a whole module and it must return the full AST of a module. It is like a macro which operates on a module not on a form. They are very powerful but easy to get messed up in.
Comments
Thanks for this; pretty much the response I was expecting but very well said.
My opinion is that functions that take quoted code do actually do the 99% job of macros pretty well. I also think creating completely new syntactic forms is fantastic for a solo project; but not so great when working in a team. So I'm left thinking what difference does it actually make. My general feeling is that I tend to write macros in Clojure just to deal with someone else's macros; i.e. macros 'layer' whereas functions compose.*
Incidentally, I've been curious about but never looked at Erlang's parse transforms because they have - in my mind at least - a big 'here be dragons' sign above them. Enough articles have warned me off to make me nervous. Would love to know more though.
* No idea if that makes sense to people. Hope so.
Regarding your point about cleaning up other people's macros.
In Elixir macros are imported into local scope only when the user explicitly asks for it. Most libraries provide a `__using___` macro that can modify current scope.
For instance, `use ExUnit.Case` allows you to write tests like this
instead of this So it basically imports a bunch of stuff for you, but only when you call `use ExUnit.Case`.The consensus in the community right now is to not get carried away with macros and DSLs. Even if your library provides a DSL, it should be based on a functional API that is mostly usable without macros.
And lastly, remember that `use`, `require`, and `import` modify only the current lexical scope. I wrote this macro[1] that replaces the built-in `|>` operator with a version that prints its output to the console. You can `use PipeInspect` inside one function and only that function's body will get the overriden implementation of `|>`.
Cheers.
[1]: https://gist.github.com/alco/9956215
Yup. But what people say and what people do is often not the same thing :).
Sure. I just wanted to stress the point that macros are local in their scope. It's nothing like monkey-patching in Ruby where importing a module can change all divisions from floats to rational numbers.
Erlang parse transforms give you access to the full AST of a whole module and it must return the full AST of a module. It is like a macro which operates on a module not on a form. They are very powerful but easy to get messed up in.