defmodule Foo do
defmacro __using__(_) do
# How to know here the methods defined in Foo / __MODULE__ ?
end
end
defmodule Bar do
def bar(a, b), do: a + b
use Foo
end
My intention is using it with __before_compile__ and defining functions with similar names and arities; i.e. Foo could define bar_debug/2, call bar/2 and print stuff.
You canât. The necessary information is only created when the module is compiled. Lets say its the very last __before_compile__ that gets run (simplification!).
If you want to gather additional information about what has defed so far, you can use @on_defintion and do some book-keeping on your own in an ETS or maybe in the PD.
Maybe it is because my Ruby background and I donât have much idea of Elixir/Erlang internals, but if the macro def has been already called the information is somewhere. Maybe it is complicated to expose or maybe it is not done because it will be a bad practice (just guessing). For sure the module it does not exist already, but it is being defined.
In fact, if I would redefine the def macro I could do a similar result, but in my case, it seems overengineering.
Well the thing about def is that it is like doing this in another âformâ:
[ 1+2
, 3+4
, some_function()
, 5+6
]
What you are conceptually asking for is for the some_function() to know the previous values in the elements before it in a list (which you could only do by passing it into the function, which of course you could do to the use call too, that is explicit, explicit is good).
Less conceptually and more âhow it is really doneâ, the do ... end body of a defmodule just creates a literal list of the abstract code, like this:
See how the âuseâ call is still just AST, when it is expanded later (pre-compilation) each node in the AST will be checked if it is a macro, if so the macro is executed with the ast of itâs arguments and the result will replace itâs node in the AST. Consequently since the AST is just a big list of tuples and such it does not know what itâs prior or after values are, just like the above list example with 1+2 and so forth.
If you want to know what functions actually end up defined at compilation then you can use the after_compile hook, but at that point you cannot edit it easily (though you could cause another recompilation with new state). The on_definition hook is generally the best way, but even then macroâs or other stuff can get involves that makes it less accurate too.
Instead of trying to transform a module of functions it is instead better to reformulate the problem. I.E. instead of asking âhowâ to do something instead ask âwhat is the end goal of what you are trying to accomplishâ, see this.
Thank you so much for the free master class I understood perfectly
Because you take your time explaining this, Iâll explain my original problem.
I have a project with more than a hundred âcommandsâ. A command in the project is an unit of change, ie RegisterUser, PublishPost, etc. All those commands have a function call which receives a different number of arguments:
Now I have to send events after the execution of each command. Depending on the command result it should send one or another: UserRegisteredEvent, UserRegistrationFailed, etc.
So my idea is basically to change the old functions call to do_call and inserting a new generic call using the Command module:
def call(input1, input2) do
do_call(input1, input2)
|> publish_events()
end
def publish_events(result) do
spawn(fn ->
generate_events(result)
|> send_events()
)
result
end
def generate_events(_), do: []
Now, the only thing I have to do in each command is to change the call to do_call and define generate_events for each possible result.
I wanted to detect the do_call function arity to define the call dinamicaly.
At the moment Iâm opting for a more explicit solution and changing the call functions to arity 1.
However, I was (wrongly) pretty sure if it was possible to do thisâŠ
Explaining all this whole situation is much more difficult to explain, so I chose to a simpler and more direct question.
Thank you for your time. I learned a lot @OvermindDL1!
Considering the events can have different arguments, Iâd make them be structâs, like a RegisterUser struct and so forth. Then you can just pass it to your do_call or so (you can even have the callback be âonâ the structs module if you wish), or completely genericize it by passing it to a protocol (not really needed in this case overall to be honest). And to send the event Iâd need to see what kind of responses you can have, but they should really be generic as well, say {:ok, someStruct} for successful results to send events and {:error, reason} for do not send or failures or so. Depending on how the events work just using a pubsub thing in elixir would probably be all around easier, but it depends on how it is used and what you have planned for it.