Supervisor and GenServer: Argument is sometimes a list, sometimes a single item

Hi all.

I’m not understanding the different forms of calling start_link for Supervisor and GenServer. I’m reading Programming Elixir by Dave Thomas, and I’m working in the section dedicated to OPT. Here’s the relevant code:

supervisor.ex

defmodule Sequence.Supervisor do
   use Supervisor

   def start_link(initial_number) do
     result = {:ok, sup } = Supervisor.start_link(__MODULE__, [initial_number])
     start_workers(sup, initial_number)
     result   
   end        

   def start_workers(sup, initial_number) do
     {:ok, stash} = Supervisor.start_child(sup, worker(Sequence.Stash, [initial_number]))
     Supervisor.start_child(sup, supervisor(Sequence.SubSupervisor, [stash]))
   end        

   def init(_) do
     supervise [], strategy: :one_for_one
  end        
end          

subsupervisor.ex

defmodule Sequence.SubSupervisor do
  use Supervisor

  def start_link(stash_pid) do
    {:ok, _pid} = Supervisor.start_link(__MODULE__, stash_pid)
  end        

  def init(stash_pid) do
    child_processes = [ worker(Sequence.Server, [stash_pid]) ]
    supervise child_processes, strategy: :one_for_one
  end        
end

server.ex

def start_link(stash_pid) do
  {:ok, _pid} = GenServer.start_link(__MODULE__, stash_pid, name: __MODULE__)
end  

Sometimes stash_pid and initial_number are passed inside of a list, and other times they are passed by themselves. I am having trouble distinguishing between which form I should use and when.

Could someone clarify this for me please?

3 Likes

The example code is correct:

Calls like Supervisor.start_link take as arguments:

  1. the module to start (to call init on) on the new process.
  2. A list of parameters to pass to this function.

So start_link takes a list, while init takes whatever arguments you want it to take, separately.

The reason for this, is that Elixir/Erlang cannot have functions with a variable number of arguments (this conflicts with pattern-matching). You can however, use the Kernel function apply. apply takes as input a so-called mfa: the first argument is the module name, the second the function name, and the third a list of arguments that are passed to that function. apply is what is also used under water inside GenServers/Supervisors.

4 Likes