Runtime “warn once” strategy

@dimitarvp thanks for chiming in. I try hard to do as much work at compile time. Here is the module in question (edited for brevity). Its perfectly acceptable to provide an arbitrary format string at runtime, the only issue being the potential of this being a performance bottleneck. It might not be in some use cases, but it will in others.

I could:

  1. Emit a log event for each time its used. Easy, but potentially noisy
  2. Emit a telemetry event. But its not really a metric so probably a perversion
  3. Encapsulate in runtime generated modules (but it doesn’t feel right to do so just for a single function call). I think this is what you meant?
  4. Find another low cost way to “warn once” at runtime. Very comfortable to make this a configurable option - and thereby emit no code and therefore no performance impact, if not required,
defmodule Cldr.Number.Backend.Decimal.Formatter do
  @moduledoc false

  def define_number_module(config) do
    alias Cldr.Number.Formatter.Decimal
    backend = config.backend

    quote location: :keep do
      defmodule Number.Formatter.Decimal do
        .....
        def to_string(number, format, options \\ [])

        def to_string(number, format, options) when is_binary(format) and is_list(options) do
          with {:ok, options} <- Options.validate_options(number, unquote(backend), options) do
            to_string(number, format, options)
          end
        end

        # Precompile the known formats and build the formatting pipeline
        # specific to this format thereby optimizing the performance.
        unquote(Decimal.define_to_string(backend))

        ....

        # For formats not precompiled we need to compile first
        # and then process. This will be slower than a compiled
        # format since we have to (a) compile the format and (b)
        # execute the full formatting pipeline.
        def to_string(number, format, %Options{} = options) when is_binary(format) do
          case Compiler.format_to_metadata(format) do
            {:ok, meta} ->
              --> warn_once("This format isn't precompiled and will be compiled in each formatting request"*
              meta = Decimal.update_meta(meta, number, unquote(backend), options)
              Decimal.do_to_string(number, meta, unquote(backend), options)

            {:error, message} ->
              {:error, {Cldr.FormatCompileError, message}}
          end
        end
      end
    end
  end
end