ArgumentError when trying to debug module and function name

I have this code in “/lib”, in a module inside a function:

Logger.debug("#{__MODULE__} test #{Atom.to_string(__ENV__.function)} test2")

It’s called from a controller. Error:

** (exit) an exception was raised:                                               
    ** (ArgumentError) argument error

For some reason __MODULE__ is nil. Why?

Can you give a more complete example?

iex(1)> defmodule M do
...(1)>   def f, do: "#{__MODULE__}"
...(1)> end
iex(2)> M.f
"Elixir.M"

So, __MODULE__ is fine…

iex(3)> defmodule M do
...(3)>   def f, do: "#{Atom.to_string(__ENV__.function)}"
...(3)> end
iex(4)> M.f
** (ArgumentError) argument error
    iex:8: M.f/0

So it is ENV.function as it seems, not __MODULE__

So, let inspect it:

iex(5)> defmodule M do
...(5)>   def f, do: "#{inspect __ENV__.function}"
...(5)> end
iex(6)> M.f
"{:f, 0}"

Oh, it returns a tuple, so the following should work:

iex(7)> defmodule M do
...(7)>   def f, do: "#{__MODULE__}.#{__ENV__.function |> elem(0)}"
...(7)> end
iex(8)> M.f
"Elixir.M.f"
4 Likes

@gilded_honour: I updated topic info (title, removed phoenix tag) to be more clear for others.

@NobbZ does not explain why you got tuple there.

__ENV__.function returns {function_name, arity}.
Function 2-element tuple is used also in other places, so be sure to remember that. :slight_smile:

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)"
2 Likes

why did you remove “phoenix”?
why did you mark it as solved?

Where did I ask to give me an example? Re-read my question – __MODULE__ is nil

As I can solve your displayed error message by altering something else than __MODULE__, it seems to be not related to your error message.

Also when you do "#{nil}" it will result in "" and not in the errormessage you have shown.

The post I made solved your problem as you have shown to us. If this is nit fixing your real problem, do show more code.

Also I gave you an example to actually figure such stuff out on your own the next time.

Also the topic was changed to actually reflect the real problem and to be easier to find for someone else having similar problems.

The term phoenix was probably removed, because your problem was unrelated to phoenix.

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.

Update: Damn, @NobbZ was faster, I type too slow :frowning:

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.

As @sztosz said:

and @NobbZ said:

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.

When I do that?
@gilded_honour, @NobbZ and @sztosz - you don’t understand my comment.

@NobbZ references to your @gilded_honour error:

and what I do is to explain it a bit more.

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 was early for me, no coffee yet. I read in OP’s comment that you marked it solved and didn’t even checked it :confused: I’m sorry.

Well, I’ve realized the topic beeing marked as solved at the same time, I’ve seen that you have commented. Therefore I assumed it as well.

And since you already altered the title of the topic and the tags, I assumed you marked as solved as well.

So I apologize, that I have blamed you without cause.

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:

  1. __MODULE__, but then it would just be interpolated into the empty string, no errormessage or crash at all.
  2. __ENV__, but then you would get an (UndefinedFunctionError) because of nil.function/0 beeing undefined
  3. __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”.

via debugger

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.

2 Likes

FTR: these steps would reproduce the __MODULE__ being nil thing:

  1. Launch iex
  2. Type __MODULE__, hit enter
  3. 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.

Yeah, but he said he is inside a defmodule block in his OP. So your steps to reproduce don’t fit his discription.

Also it does not show the OPs error.

If there is really a way to have __MODULE__ beeing nil while inside of a module that’s a compiler bug and needs to get fixed!

1 Like

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.

As I have already shown in ArgumentError when trying to debug module and function name, nothing beeing nil in that snippet will ever give us OPs error…