Conditional Compilation of @callback and @impl

As a library writer my objectives are:

  1. Be useful (ok, obvious) and reliable
  2. Have good documentation
  3. Deliver responsive support
  4. Support multiple Elixir releases in a single library release
  5. And to do so without emitting compiler warnings since as a consumer, compiler warnings in a lib don’t inspire confidence.

Sometimes callbacks change between Elixir releases (and I’m a contributor to that). And I can’t find a way to conditionally compile @callback and @impl to achieve (4) and (5) above. Which means depending on which Elixir release I get:

warning: got "@impl true" for function inspect_time/5 but no behaviour specifies such callback.....

I’ve tried wrapping @imp true in a conditional like

if Version.compare(System.version(), "1.10.0-dev") in [:eq, :gt] do
  @impl true
end

Unfortunately the @impl true is inserted into the code anyway. Any ideas on how to conditionally compile @callback and @impl would be appreciated.

I know I could just remove all the @impl true directives but that seems a last resort.

1 Like

Here’s how we achieve a very similar thing on Decimal, we set @doc since: "..." only on Elixir versions that supports it:

defmodule Decimal.Macros do
  @moduledoc false

  defmacro doc_since(version) do
    if Version.match?(System.version(), ">= 1.7.0") do
      quote do
        @doc since: unquote(version)
      end
    end
  end
end
defmodule Decimal do
  # ...
  import Decimal.Macros

  @doc """
  Check if given number is positive
  """
  doc_since("1.5.0")
  @spec positive?(t) :: boolean
end

See: https://github.com/ericmj/decimal/blob/v1.7.0/lib/decimal.ex#L1

4 Likes

Much appreciated!

1 Like