__ENV__.function returns {function_name, arity}.
Function 2-element tuple is used also in other places, so be sure to remember that.
Complete example to explain how it works should looks like:
defmodule Example do
def sample do
{name, arity} = __ENV__.function
"Elixir." <> rest = Atom.to_string(__MODULE__)
"called '#{name}' in '#{rest}' with #{airty} argument(s)"
end
end
Example.sample
# returns:
"called 'sample' in 'Example' with 0 argument(s)"
How did you check if __MODULE__ is really nil? Because your example code, as @NobbZ explained has a bug, and the error message is more than likely referring to passing tuple to Atom.to_string instead of atom, rather than __MODULE__ being nil, because even if it was nil, there would be no error associated with that. If it was nil, there would be simply nil substituted for it, and nothing would be printed. Simply try for example this in your code and see what happens: "#{nil} <- was there an error here?"
I’m not defending @Eiji marking it solved. But you, sadly did jump to his throat without even reading @NobbZ’s answer. But one thing @Eiji was correct is to remove phoenix tag, because it really has nothing to do with phoenix per se.
I’m not happy with marking it solved in only a matter of hours without waiting for the OP to comment as well. I think we should wait for 2 or 3 business days to do so, and give the OP the opportunity to actually give out more details and if it helped or not.
i.e. it’s not only my opinion.
This is not Phoenix issue. You are calling function in /lib directory - as you said. No matter if you call this function from Phoenix or Erlang NIF. It’s a problem with exactly that function.
Both __MODULE__ and __ENV__ comes from Elixir and not from Phoenix.
where by it I mean __ENV__.function
I don’t see anything like: complete answer to your question.
I don’t marked it as solved - even more I don’t have the ability to do it.
I have similar feelings. In my opinion every question is not solved unless OP mark it as soled, because I believe that OP have rights to request for explanation for each answer. I believe that question is solved not when answer is available, but when OP understand it and can use it in his special case.
Finally let’s back to your problem:
I can’t reproduce it in normal function declared with def, but it’s possible when you are using macros like:
defmodule Example do
defmacro sample do
quote do
__MODULE__
end
end
end
require Example
Example.sample # returns nil
This example returns nil because quoted expression in not executed in Example module. Macros accepts arguments with Macro.t type and returns result also with that type (i.e. literal or expression) and finally expression is used outside of Example, but … it also does not like answer for your problem, because in that case you should see controller module name instead of nil.
I just want to explain only one case that I can see when __MODULE__ returned from function (macros are functions too) could return nil. I don’t see any other case and therefore I can’t reproduce it.
Can you reproduce it with new Elixir/Phoenix app (just create new app and place your file from /lib directory into this new project)? If so please share a minimal example to reproduce it. If not please say if you can share you project, so we can look at it and therefore we could try to fix this issue myself.
It is not. Let me list things that can be nil (even if very unlikely to ever happen) in your code, and what would happen then:
__MODULE__, but then it would just be interpolated into the empty string, no errormessage or crash at all.
__ENV__, but then you would get an (UndefinedFunctionError) because of nil.function/0 beeing undefined
__ENV__.function, but then Atom.to_string/1 would return "nil"
So if, and only if, really something is nil in the snippet you have shown to us, it would not result in the error message you have shown to us.
In fact, the only way to reproduce your error in an isolated manor, is as I have shown in my direct reply. We have also shown multiple alternatives to get some output that might be similar to what you want.
If you still insist on something beeing nil, than isolate that thing in a minimal example, that shows the nil-value and not an arbitrary error.
Until you have done so, I’ll mark this issue as solved on my perosnal list and I wish you luck with your “problem”.
Yeah. Because __MODULE__ doesn’t exist at runtime anymore, it is substituted by its value at compile time.
Again, show us code that prints out the value nil for __MODULE__and shows your originally posted error, or we won’t believe it ever happened.
Also, in a language that relies on Macro-Expansion as heavy as elixir, a classical debugger doesn’t help much. The debugger doesn’t know how macro calls are altered during compiletime. Also classical (step) debugging has many problems in distributed and concurrent programs due to the impossibility to stop everything at once. Also the BEAM doesn’t allow to stop more than one during debugging, so you are likely to get timeouts or syncronisation failures when debugging in a process.
FTR: these steps would reproduce the __MODULE__ being nil thing:
Launch iex
Type __MODULE__, hit enter
See it is nil.
I agree though. It would be good to see some code that is actually reproducing this issue. Talking about it is great, but having the code right there which shows a clear and concise way to reproduce this issue is 100% the best way.
Ok, but still __MODULE__ being nil with code Logger.debug("#{__MODULE__} test #{Atom.to_string(__ENV__.function |> elem(0))} test2")will not give you error like this
** (exit) an exception was raised:
** (ArgumentError) argument error
There is really no point in guessing game until we have a code that is correct in terms of function calls, and can reproduce __MODULE__ being nil inside actual module.