# Funções nomeadas

A função é o principal elemento das linguagens funcionais (grande surpresa an?) e tem como objetivo realizar comportamentos.&#x20;

{% hint style="info" %}
**Aridade**\
\
De forma simples, a [aridade](/conceitos/aridade.md) é a quantidade de argumentos que uma função recebe.

Uma função `login` que recebe `user` e `password` por parâmetro tem aridade 2 e é representado com o nome da função, barra (/) e o número da aridade. Exemplo:\
\
`login(user, password) -> login/2`\
\
Veja mais no [capítulo de Aridade](/conceitos/aridade.md)
{% endhint %}

Funções nomeadas devem existir somente dentro de módulos e são declaradas com `def/2` e `defp/2` para funções privadas. Como por exemplo:

<pre class="language-elixir" data-line-numbers><code class="lang-elixir">defmodule Authenticate do
<strong>  def login(user, password) do
</strong>    # ...
  end
  
<strong>  defp create_session(user), do: # ...
</strong>end
</code></pre>

Vamos criar um novo teste em nosso projeto onde iremos fazer uma soma simples. Na pasta `test` crie um novo arquivo chamado `math_test.exs` e nele utilizaremos nosso primeiro `describe`, descrevendo o que está sendo testado.

{% hint style="info" %}
**Describe**

\
O `describe/2` descreve um grupo de testes que tem correlação. Assim podemos criar diversos cenários para uma mesma função que está sendo testada. Exemplo:<br>

* Quando a função x funciona
* Quando a função x não funciona devido a parâmetros errados<br>

Normalmente o describe recebe o `module + função sendo testada + aridade`&#x20;
{% endhint %}

Podemos tirar algumas vantagens quando utilizamos describe. Uma delas é servir de documentação. Então vamos pensar. Precisamos fazer uma soma (função) e essa soma irá somar dois valores x e y (parâmetros). Analisando isso, podemos presumir que o contrato de nossa função seja algo assim `Math.sum/2`. Vamos adicionar isso a nossa describe para facilitar o entendimento

<pre class="language-elixir" data-title="test/math_test.exs" data-line-numbers><code class="lang-elixir">defmodule MathTest do
  use ExUnit.Case

<strong>  describe "Math.sum/2" do
</strong>    # ...
  end
end

</code></pre>

Criaremos o primeiro bloco de teste  para quando passarmos os parâmetros corretos.&#x20;

{% hint style="info" %}
**Parâmetros**

\
Forma de injetar dados dentro de funções de forma a poder ser usada la dentro. A assinatura se da a criação da função usando `def/2`, definindo o nome da função e em seguida adicionando parênteses. Dentro dos parênteses adicionamos as variáveis posicionais. \
\
`def nome_da_funcao(parametro_1, parametro_2)`\
\
Assim você poderá passar dados para dentro da função e os usa-los lá.\
\
`nome_da_funcao(5, 10)`&#x20;
{% endhint %}

Vamos adicionar ao código o bloco de teste usando a função `test/2`

<pre class="language-elixir" data-title="test/math_test.exs" data-line-numbers><code class="lang-elixir">defmodule MathTest do
  use ExUnit.Case

  describe "Math.sum/2" do
<strong>    test "when successed return result" do
</strong>      
    end
  end
end

</code></pre>

Precisamos agora entender o que seria um teste bem sucedido aqui e para isso devemos seguir algumas etapas do TDD para se tornar mais simples

1. Configurar o teste
2. Executar a chamada
3. Criar afirmações

Para configurar o teste, precisamos da função a ser chamada e dos parâmetros que queremos passar, então executamos essa função com os parâmetros e guardados sua resposta, para podermos utilizarmos em nossas afirmações.

Pelo básico, Queremos a soma do valor `x = 1` e  `y = 7` e a resposta deve ser 8. Vamos converter isso para o código

{% code title="test/math\_test.exs" lineNumbers="true" %}

```elixir
defmodule MathTest do
  use ExUnit.Case

  describe "Math.sum/2" do
    test "when successed response the result" do
      # configurando
      x = 1
      y = 7
      
      # Executando a função
      result = Math.sum(x, y)
      
      # criando afirmações
      assert result == 8
    end
  end
end
```

{% endcode %}

Vamos rodar isso e ver o relatório

```shell
mix test
warning: Math.sum/2 is undefined (module Math is not available or is yet to be defined)
  test/math_test.exs:11: MathTest."test Math.sum/2 when successed response the result"/1

.

  1) test Math.sum/2 when successed response the result (MathTest)
     test/math_test.exs:5
     ** (UndefinedFunctionError) function Math.sum/2 is undefined (module Math is not available)
     code: result = Math.sum(x, y)
     stacktrace:
       Math.sum(1, 7)
       test/math_test.exs:11: (test)


Finished in 0.03 seconds (0.00s async, 0.03s sync)
2 tests, 1 failure
```

Possuímos nosso primeiro erro. Decidimos usar TDD e o teste vem antes do código a ser testado, então, não possuímos o código e o teste avisou isso para nós. `Math.sum/2 is undefined`. Vamos criar o módulo Math com a função sum com 2 de aridade.

{% hint style="info" %}
**TDD**

\
**Testing driven design** tem como regra guiar nosso código iniciando ele pelos testes. Uma vez que ele falhe temos um ponto de ação a fazer. Sempre focando no menor esforço a se fazer para o teste passar.\
\
[Leia mais sobre](https://martinfowler.com/bliki/TestDrivenDevelopment.html)
{% endhint %}

Crie o novo arquivo e adicione o mínimo necessários para seguirmos em frente.

{% code title="lib/math.ex" lineNumbers="true" %}

```elixir
defmodule Math do
  def sum(_x, _y) do

  end
end

```

{% endcode %}

{% hint style="info" %}
**Utilizando prefixo underline (\_)**

\
Quando temos parâmetros e não o utilizamos, o interpretador nos emite um aviso dizendo que a variável não está sendo utilizada.\
\
`warning: variable "y" is unused (if the variable is not meant to be used, prefix it with an underscore) lib/math.ex:2: Math.sum/2`

Para esse aviso sumir, podemos colocar como prefixo o underline (\_) e ele irá ignorar essa validação.

`def sum (_x, _y) do`  &#x20;
{% endhint %}

Salve o arquivo e vamos tentar rodar o teste mais uma vez

```shell
mix test
Compiling 1 file (.ex)
Generated hello_world app
.

  1) test Math.sum/2 when successed response the result (MathTest)
     test/math_test.exs:5
     Assertion with == failed
     code:  assert result == 8
     left:  nil
     right: 8
     stacktrace:
       test/math_test.exs:14: (test)


Finished in 0.02 seconds (0.00s async, 0.02s sync)
2 tests, 1 failure
```

Temos um erro diferente (progresso!). O relatório nos conta que o lado esquerdo de nossa assertion está `nil`, mas o lado direito esperava `8` . Nossa função não esta retornando nada. Podemos ler assim: o resultado da função esta nulo enquanto o esperado no teste é 8.&#x20;

Agora podemos implementar nosso código real. Vamos fazer a soma e retornar o valor.

<pre class="language-elixir" data-title="lib/math.ex" data-line-numbers><code class="lang-elixir">defmodule Math do
  def sum(x, y) do
<strong>    x + y
</strong>  end
end
</code></pre>

Não precisamos de nenhuma palavra chave para indicar que um valor vai ser retornado na função. Elixir faz isso na última linha da função.

Basta agora rodar o teste e ver tudo funcionar.

```shell
mix test
Compiling 1 file (.ex)
..
Finished in 0.01 seconds (0.00s async, 0.01s sync)
2 tests, 0 failures
```

## Conclusão

Vimos o básico de funções. Descobrimos que uma função é definida por seu nome e sua aridade. Que toda função nomeada deve estar dentro de um módulo e que podemos passar dados para dentro dela usando parâmetros posicionais.

Entendemos um pouco mais sobre TDD e criamos nosso primeiro teste do zero.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://aprenda.cafecomelixir.com.br/basico/funcoes/funcoes-nomeadas.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
