# Warning when using function variants with different keyword options

I am a newbie to Elixir so please forgive any foolishness.

I have an ‘outer’ function called foo that needs to provide two main variants, that I want to be selected using a single-entry Keyword list, e.g. do_it: :one, or do_it: :two, with :two being the default case.

The two variants are such that one is a trivial extension of the other, so that the extended form can call the non-extended form, after performing a small amount of pre-processing on the input argument.

I have attempted to implement this behaviour as follows:

``````  # the extended case, indicated by the option: keyword
def foo(value, do_it: :one) do
# do some pre-processing

# then call the 'core' processing, with no keyword
foo(val)
end

# the non-extended case, called by the extended case, keyword defaults to nil
def foo(value, _opt \\ nil) do
#  do the main work
end

# the 'parent' case, which may optionally be passed the do_it: keyword pair
def bar(value, opt \\ nil) do
case foo(value, opt) do
case1 -> ...
case2 -> ...
end
end

# a typical call, invoking the extended case
bar(my_value, do_it: :one)
``````

Unfortunately, when I use this approach, I get the following compiler warning.

``````warning: def foo/2 has multiple clauses and also declares default values. In such cases, the default values should be defined in a header. Instead of:

def foo(:first_clause, b \\ :default) do ... end
def foo(:second_clause, b) do ... end

one should write:

def foo(a, b \\ :default)
def foo(:first_clause, b) do ... end
def foo(:second_clause, b) do ... end
``````

Now, I am sure that this explanation is meant to clarify things, but to me it is just
adding confusion. I realise it’s a big ask, but could somebody sugest how my code should
be structured to avoid this warning? The suggested improvment just doesn’t make
sense to me - e.g. what are :first_clause and :second_clause??

Hello and welcome,

The easiest way to fix this would be…

``````  def foo(value, opt \\ nil)
def foo(value, do_it: :one) do
# do some pre-processing

# then call the 'core' processing, with no keyword
foo(val)
end

# the non-extended case, called by the extended case, keyword defaults to nil
def foo(value, opt) do
#  do the main work
end
``````

But it might not be the best way.

First, nil is not a keyword. I would rather use

``````opt \\ []
``````

to ensure return type is a keyword.

Using _opt means You don’t care about opt… another way to fix it is to use arity of 1

``````def foo(value) do
``````

This would also solve the problem, if the core function does not have params.

Maybe this?

``````  def foo(value, opt \\ [])
def foo(value, do_it: :one) do
# do some pre-processing

# then call the 'core' processing, with no keyword
foo(val)
end

# the non-extended case, called by the extended case, keyword defaults to nil
def foo(value, opt) do
#  do the main work
end
``````

BTW You should not think in OOP terms, it is not inheritance, it’s composition. You compose functions to make a bigger one. Not function A is extending function B.

1 Like

Hi Koko, thanks for your prompt reply, which makes a lot of sense. Unfortunately, first time I read your suggestion, I missed the point about having two ‘declarations’ of the defaulted case. I’ve never seen this done before (I told you I was a newbie ). Definitely, something to research!

I take your point wrt OOP although I’m not sure that one function extending another is really a symptom of this - that just how my logic works in this case. I appreciate how the terminology may be confusing though - especially used to the word ‘extend’. Fwiw, I do sometimes code in an OOP way: muscle memory more than anything else In particular, i keep typing things like snafu.map(fn) rather than Enum.map(snafu,fn) Blame Scala for that…