How do you personally handle start_link with no args?

I think I’m getting the hang of elixir pretty well (I love it!). I have this stylistic question that bothers me that I’d like to know.

What is your personal way to handle a start_link in a server when you dont need the arguments. Here’s the ways I see. Id love to hear your preferred way:

Style A

App: {SomeServer, []}
Code:

def start_link(state) do
  GenServer.start_link(__MODULE__, state)
end

This way was suggested by someone here, but it seems really confusing because I constantly have to ask myself what state is or if I’m actually using it.

Style B

App: {SomeServer, :ok}
Code:

def start_link(:ok) do
  GenServer.start_link(__MODULE__, :ok)
end

This way seems OK but 3 redundant :ok (or []) seems weird. I’d love if it could be something involving _ but that wont work because I also have to put something in the expression.

Any other ways you see too would be great, thankss!

Edit: I keep seeing examples where people don’t use any args, but whenever I try to do that it fails. How might I initiate a call to my module in application.ex such that I don’t need to pass args?

@9mm: If I remember correctly for supervisors you need to have one argument. Fortunately you can ignore it and set default value:

def start_link(_opts \\ []), do: GenServer.start_link(__MODULE__, state)

So it’s as easy to call manually (without any argument) as using it with your app’s supervisor.

Optionally you can just set opts (without ignore and default value) and pass some data using supervisor, but it’s not your use case.

1 Like

How would I call start_link without arguments from within application.ex? That is also a point that I can’t figure out (it seems you could do this with the old Supervisor.Spec)

@9mm Writting from memory:

defmodule MyApp.Application do
  @moduledoc false

  use Application

  def start(_type, _args) do
    import Supervisor.Spec, warn: false
    children = [SomeServer] # not in tuple
    Supervisor.start_link(children, strategy: :one_for_one, name: MyApp.Supervisor)
  end
end

Ah yeah, I do know its possible in Supervisor.Spec but that is deprecated I believe so I was trying to use the new way.

Edit: Sorry… I realized I phrased my previous message poorly and it wasnt clear I didnt want to use that

@9mm It’s deprecated only from 1.8, so no need to worry. I did not even received any warning yet. :077:

If I remember correctly in new child specification you have 2 ways of doing it:

defmodule SomeServer do
  # …

  def child_spec(_opts \\ []) do
    %{
      id: __MODULE__,
      start: {__MODULE__, :start, []},
      type: :worker,
      restart: :permanent,
      shutdown: 500
    }
  end
end

Or if you do not own this module you can do it like:

children = [
  %{
    id: SomeServer,
    start: {SomeServer, :start_link, []}
  }
]

Edit: Here is example error which explains it:

** (Mix) Could not start application my_app: exited in: MyApp.Application.start(:normal, [])
    ** (EXIT) an exception was raised:
        ** (ArgumentError) The module MyApp was given as a child to a supervisor
but it does not implement child_spec/1.

If you own the given module, please define a child_spec/1 function
that receives an argument and returns a child specification as a map.
For example:

    def child_spec(opts) do
      %{
        id: __MODULE__,
        start: {__MODULE__, :start_link, [opts]},
        type: :worker,
        restart: :permanent,
        shutdown: 500
      }
    end

Note that "use Agent", "use GenServer" and so on automatically define
this function for you.

However, if you don't own the given module and it doesn't implement
child_spec/1, instead of passing the module name directly as a supervisor
child, you will have to pass a child specification as a map:

    %{
      id: MyApp,
      start: {MyApp, :start_link, [arg1, arg2]}
    }

See the Supervisor documentation for more information.

            (elixir) lib/supervisor.ex:639: Supervisor.init_child/1
            (elixir) lib/enum.ex:1314: Enum."-map/2-lists^map/1-0-"/2
            (elixir) lib/supervisor.ex:625: Supervisor.init/2
            (elixir) lib/supervisor.ex:576: Supervisor.start_link/2
            (kernel) application_master.erl:277: :application_master.start_it_old/4
1 Like

Awesome, thanks… this solved it perfect:

%{id: ThingMajig, start: {ThingMajig, :start_link, []}},

Also now i see it very clearly in the docs…

Reading the docs isnt the hard part, its when I haev 95 questions all in my mind at the same time its overwhelming to read docs because it just introduces more lol. I need to let the consumers (my brain) churn on some workload

%{id: ThingMajig, start: {ThingMajig, :start_link, []}},

is equivalent to

ThingMajig

if ThingMajig exports a child_spec function

1 Like