Should I provide typespec for each function clause?

When creating multiple clauses for a function, should I provide typespec for each one? Example:

@spec foo([]) :: {:error, any}
def foo([]) do
  ...
  {:error, ...}
end

@spec foo([integer]) :: {:ok, any}
def foo(some_list) do
  ...
  {:ok, ...}
end

…or is something like this preferrable?


@spec foo([integer]) :: {:ok, any} | {:error, any}

def foo([]) do
  ...
  {:error, ...}
end

def foo(some_list) do
  ...
  {:ok, ...}
end

Thanks!

Both work, internally there’s no difference and the multiple specs will become unions of all separate specs anyways.

I’ll typically use the second approach.

The different function heads which ultimately need to be defined by the spec are typically grouped together and having a spec at the top of that group makes for a reasonable signpost in the source code for the beginning of that group.

1 Like

You are defining ONE function so it should be for that function which you give the typespec.

6 Likes