Search code examples
elixirargument-unpacking

Use a tuple as arguments for a function in Elixir


I'm writing a game engine in Elixir. (Yes, I know it's not a language inherently suited to that – the point is to look at how the use of an atypical language affects the structure of the result.)

As such, I have several supervisors to be run on game start – but what exactly they should be supervising depends on the game. My thought had been to have the user list out the necessary children, plus arguments and options, in the config.exs file as a list of tuples, and then the supervisor itself would simply pull those tuples from the application environment and use their contents as arguments to worker\2 (or worker\3, as appropriate).

However, I can't find any Elixir equivalent to Python's tuple-unpacking. I could do it myself for this specific case with a simple function:

def unpack_worker({module, args}) do
  worker(module, args)
end

def unpack_worker({module, args, opts}) do
  worker(module, args, opts)
end

But that feels clumsy at best, and would have to be written again for every function for which I might need this kind of configurability.


Solution

  • I believe you're looking for Tuple.to_list/1 and apply/3:

    With those, you can invoke a function of the correct arity based on the contents of the tuple:

    def unpack_worker(args) do
      apply(__MODULE__, :worker, Tuple.to_list(args))
    end
    

    If you now call unpack_worker({}), it'll call worker(), unpack_worker({:foo}) will call worker(:foo), and so on.

    Demo:

    defmodule A do
      def worker, do: IO.puts 0
      def worker(_), do: IO.puts 1
      def worker(_, _), do: IO.puts 2
      def worker(_, _, _), do: IO.puts 3
    
      def unpack_worker(tuple), do: apply(__MODULE__, :worker, Tuple.to_list(tuple))
    end
    
    A.unpack_worker({})
    A.unpack_worker({:a})
    A.unpack_worker({:a, :b})
    A.unpack_worker({:a, :b, :c})
    

    Output:

    0
    1
    2
    3