Pollution. By adding functions to the macro, every client that uses your behaviour has them, possibly resulting in a fat API that some clients may not need at all.
It is implicit functions and behaviour VS explicit. The Elixir community prefers explicitness, so having a bunch of functions in a client that no one knows where they come from (because they were injected by use from some behaviour ) is not ideal
Testing such functions can only be done via fake clients, or mocks.
And I think this is it, (feel free to let me know if there are more).
So, with all this in mind:
Why would anyone inject anything into __using__?
Why do we even need it? Why not just use @behaviour?
What good use cases can it have?
I am looking for answer of any format, tutorials to read, opinions from member, books, anything.
Please do share your mind!
The purpose of __using__ is to inject code. You want to limit doing this (i.e. don’t do it just because you can).
use can be leveraged to inject repetitive code in modules, e.g. in ExUnit the test files have use ExUnit.Case which does a bunch of stuff, among which making it possible to e.g. use test functions in the file.
Imho the only reason to define functions within defmacro __using__, do: … is if that function needs to be compiled using information about the module, which is calling use MyModule or from the options passed to the macro.
If the above does not apply, but you still want to make sure a function is directly callable within MyModule just add an import MyUsedModule with the __using__ macro.
To your 2. question: I don’t use __using__ with behaviours unless I have a case where – knowing the module using my behaviour – I can implement functions for that user, which I couldn’t do without knowing that module. Like the child_spec/1 function of GenServer. It needs the module name, but nothing else to be implemented. So it’s much more convenient to have people do use GenServer instead of @behaviour GenServer and they need to copy/paste some functions.
I feel like people coming to elixir often assume behaviours need __using__ because GenServer is using that functionality, which is neither true nor to be recommended as default way for behaviours.
So I understand that __using__ is useful when I want to create a Domain Specific Language, like the one we use to make tests. I understand this argument from Metaprogramming with Elixir but this is such a specific use case that I have never encountered one during my whole career (do note I am starting in Elixir, perhaps here it is more common?).
In this specific case ( of ExUnit ) I wouldn’t mind writting ExUnit.Case.test instead of just test, specially because then I can use alias to abbreviate it to something like T.test or something similar and have the dependency be explicitly visible.
Why not pass that information as parameters to the functions of your behaviour then?
So, you’d do it to provide a default implementation of a function for your clients to (maybe) override?