How to inject code depending on Elixir API availability?

While working on a project that uses old Elixir version (1.6) I found myself not being able to use the ~U sigil. No worries, let’s make an imitation, no problem.

However, locally I work with Elixir 1.13 and I was wondering how can I use conditional definition of this homegrown sigil.

Here’s what I tried and it doesn’t work:

defmodule Helpers do
  unless macro_exported?(Kernel, :sigil_U, 2) do
    def sigil_U(text_datetime, _modifiers) do
      {:ok, datetime, 0} = DateTime.from_iso8601(text_datetime)
      datetime
    end
  end
end

defmodule Xyz do
  unless macro_exported?(Kernel, :sigil_U, 2) do
    import Helpers, only: [sigil_U: 2]
  end

  def test() do
    ~U(2021-12-03 13:14:23.000000Z)
    |> IO.inspect()
  end
end

Running mix run -e 'Xyz.test' fails with:

** (CompileError) lib/xyz.ex:14: cannot import Helpers.sigil_U/2 because it is undefined or private

This is ran with Elixir 1.13 so macro_exported?(Kernel, :sigil_U, 2) should return true and thus the import block should not be evaluated.

I also tried with if Version.compare(System.version(), "1.9.0") == :lt to no avail.

I know I’ve solved something similar before but can’t remember how and I am sure I am missing something obvious since I haven’t meddled with metaprogramming for a while.

Any ideas what am I doing wrong?

Wouldn’t it be easier to unconditionally import the sigil paired with import Kernel, except:?

Not really because my implementation is not as good. I want to use the builtin sigil when it’s available.

no expert here, but this seems to work:

defmodule Helpers do
  unless macro_exported?(Kernel, :sigil_U, 2) do
    def sigil_U(text_datetime, _modifiers) do
      IO.inspect(text_datetime)
      {:ok, datetime, 0} = DateTime.from_iso8601(text_datetime)
      datetime
    end
  end
end

defmodule Xyz do
  import Helpers

  def test() do
    ~U(2021-12-03 13:14:23.000000Z)
    |> IO.inspect()
  end
end
mix run -e "Xyz.test"
Compiling 1 file (.ex)
~U[2021-12-03 13:14:23.000000Z]
2 Likes

Hah, that’s why we have to ask other people every now and then. Didn’t even occur to me to import unconditionally. :slight_smile:

Thanks!

No probs, original is here :slight_smile: