Warning: this check/guard will always yield the same result. Should I do this differently?

I have an is_nil guard against a module attribute compiled with Application.get_env. Something like the code below.

defmodule Foo do
  @secret Application.get_env(:foo, :secret)

  # Always return :ok if secret isn't set (i.e. in development)
  def check_secret(_) when is_nil(@secret), do: :ok
  def check_secret(secret) when secret == @secret, do: :ok
  def secret(_), do: :error
end

This gives me a warning though: warning: this check/guard will always yield the same result. Can I suppress this warning? Or should I solve this differently?

Any help/pointers is appreciated :slight_smile:

Yupp…

Draft:

def check(secret), do: check(secret, @secret)

defp check(_, nil), do: :ok
defp check(secret, secret), do: :ok 
defp check(_, _), do: :error

Might get better optimized and costs less reductions.

5 Likes

I ‘think’ this would work (but untested of course):

defmodule Foo do
  secret = Application.get_env(:foo, :secret)

  # Always return :ok if secret isn't set (i.e. in development)
  def check_secret(_) when unquote(quote(generated: true, do: is_nil(unquote(secret))), do: :ok
  def check_secret(secret) when unquote(quote(generated: true, do: secret == unquote(secret)), do: :ok
  def secret(_), do: :error
end

Which of course you could wrap up in a macro if used often (or to make it more readable). You ‘might’ need to mark the def itself as generated, but a macro could do that easily too (or pipe it through, just be careful not to mark the body as generated to prevent hiding issues inside).

But @NobbZ way is the best for generic calls and readability, don’t use the above unless you are optimizing for absolute efficiency at the cost of readability.

Do you have a special reason to use that module attribute? Some name it an anti-pattern, discussion on using (secret) config info in this way and alternatives you can find here:

https://medium.com/nebo-15/runtime-configuration-migrations-and-deployment-for-elixir-applications-6295b892fa6a

When you do not use the module attribute (see links above) you can write:

  defmodule Foo do
    def check(secret), do: if Application.get_env(:foo, :secret) in [secret, nil], do: :ok, else: :error
  end

otherwise

  defmodule Foo do
    @secret Application.get_env(:foo, :secret)
    def check(secret), do: if @secret in [secret, nil], do: :ok, else: :error
  end