Function with default arguments and explicitly declared clauses

The general way of doing this is to declare a single head with all the optional arguments, and then a single function with the maximum number of arguments :smiley:

  def lookup(params, place_id \\ default_place(), company_id \\ default_company(), date \\ default_date())

  def lookup(params, place_id, company_id, date) do
    # do stuff
  end
  
  def lookup(params, place_id, company_id, date) do
    # another clause
  end

Note that when you do this:

@default DateTime.utc_now()

It is evaluated at compile time. So the default date will be the date at the moment of compilation, which is probably not what you want.

But you can use function calls as default arguments:

  def my_default() do
    DateTime.utc_now()
  end

  def my_fun(date \\ my_default()) do
    #
  end

Because this:

  def my_fun(date \\ my_default()) do
    #
  end

Compiles as the same as this:

  def my_fun() do
    my_fun(my_default())
  end

  def my_fun(date) do
    #
  end

Edit:

If you regenerate Erlang code from this module:

defmodule Demo do
  def my_fun(a \\ :w, b \\ :x, c \\ :y, d \\ :z)

  def my_fun(a, b, c, d) do
    [a, b, c, d]
  end
end

You get a bunch of attribute and these function definitions:

my_fun() -> my_fun(w, x, y, z).

my_fun(_@1) -> my_fun(_@1, x, y, z).

my_fun(_@1, _@2) -> my_fun(_@1, _@2, y, z).

my_fun(_@1, _@2, _@3) -> my_fun(_@1, _@2, _@3, z).

my_fun(_a@1, _b@1, _c@1, _d@1) ->
    [_a@1, _b@1, _c@1, _d@1].