Normalmente você verá as funções com essa representação map/2 ou Enum.map/2. Esse número após a barra se chama aridade. Ela vem da matemática onde significa o número de argumentos ou de operandos que uma função ou operação requer.
Ele tem o mesmo significado no Elixir. Ele indica quantos argumentos essa função necessita para ser executada. No exemplo acima temos o Enum.map/2. Leia-se que a função map do módulo Enum precisa de dois argumentos para poder ser utilizado.
Isso serve para as funções que você cria também. Vamos a um exemplo. Teremos uma função simples chamada multiple do módulo Math que multiplica 2 números x e y.
Podemos representar isso dessa forma Math.multiple/2. Uma vez que você passe isso para alguém que entenda de aridade, ele entenderá o que é necessário para essa função.
Vamos ao teste
test/math_test.exs
defmoduleMathTestdouseExUnit.Case describe "multiple/2"do test "success: return the result"do assert Math.multiple(3,5) ==15endendend
Rodando isso teremos um relatório de erro pois não possuímos a função.
mixtesttest/math_test.exswarning:Math.multiple/2isundefinedorprivatetest/math_test.exs:6:MathTest."test multiple/2 success: return the result"/11) test multiple/2 success: return the result (MathTest)test/math_test.exs:5** (UndefinedFunctionError) functionMath.multiple/2 is undefined or privatecode:assertMath.multiple(3,5) ==15stacktrace: (hello_world0.1.0) Math.multiple(3,5)test/math_test.exs:6: (test)Finishedin0.02seconds (0.00s async,0.02ssync)1test,1failure
Agora que possuímos a representação e o teste de nossa função, vamos criar a implementação dela.
lib/math.ex
defmoduleMathdodefmultiple(x, y) do x * yendend
mix test test/math_test.exsCompiling1file (.ex).Finishedin0.01seconds (0.00s async,0.01s sync)1 test,0 failures
Tudo funcionando. Mas, sabendo que nossa função é dois de aridade, o que acontece quando mandamos apenas um argumento? Vamos criar um teste para isso
test/math_test.exs
defmoduleMathTestdouseExUnit.Case describe "multiple/2"do# ... test "fail: Insufficient Arguments"doMath.multiple(3)endendend
testtest/math_test.exswarning:Math.multiple/1isundefinedorprivate.Didyoumean:*multiple/2test/math_test.exs:10:MathTest."test multiple/2 fail: Insufficient Arguments"/11) test multiple/2 fail: Insufficient Arguments (MathTest)test/math_test.exs:9** (UndefinedFunctionError) functionMath.multiple/1 is undefined or private. Did you mean:*multiple/2code:assertMath.multiple(3) ==nilstacktrace: (hello_world0.1.0) Math.multiple(3)test/math_test.exs:10: (test).Finishedin0.02seconds (0.00s async,0.02ssync)2tests,1failure
Quando não encontra uma função com a especificação enviada, recebemos uma exceção dizendo que função não foi definida. Também recebemos uma sugestão de que talvez o que queremos seja a função multiple/2 e não multiple/1.
Podemos fazer esse teste passar dizendo que esperamos que falhe quando isso aconteça. Vamos alterar nosso teste para esperar por iso.
test/math_test.exs
defmoduleMathTestdouseExUnit.Case describe "multiple/2"do# ... test "fail: Insufficient Arguments"do expected ="function Math.multiple/1 is undefined or private" assert_raise UndefinedFunctionError, expected,fn->Math.multiple(3)endendendend
Ele é uma função auxiliadora do ExUnit que captura uma exceção, assim podemos criar testes que esperamos que uma implementação falhe quando algo sai do esperado. Algumas vezes esse caso é necessário.
Também podemos usar a aridade para escolher a função a ser rodada de mesmo nome. Vamos fazer outro teste.
defmodulePersonhTestdouseExUnit.Case describe "say_my_name/2"do test "success: when passing two arguments"do assert Person.say_my_name("Iago","Effting") =="Seu nome completo é Iago Effting"endendend
Você pode rodar e ver que o módulo e função não foram definidas. Vamos cria-la.
lib/person.ex
defmodulePersondodefsay_my_name(first_name, last_name) do"Seu nome completo é #{first_name}#{last_name}"endend
defmodulePersonhTestdouseExUnit.Case describe "say_my_name/2"do# ... test "success: when passing one argument"do assert Person.say_my_name("Iago") =="Seu primeiro nome é Iago Effting"endendend
mixtesttest/person_test.exswarning:Person.say_my_name/1isundefinedorprivate.Didyoumean:*say_my_name/2test/person_test.exs:10:PersonTest."test say_my_name/2 success: when passing one argument"/1..1) test say_my_name/2 success: when passing one argument (PersonTest)test/person_test.exs:9** (UndefinedFunctionError) functionPerson.say_my_name/1 is undefined or private. Did you mean:*say_my_name/2code:assertPerson.say_my_name("Iago") =="Seu primeiro nome é Iago"stacktrace: (hello_world0.1.0) Person.say_my_name("Iago")test/person_test.exs:10: (test).Finishedin0.02seconds (0.00s async,0.02ssync)2tests,1failure
O relatório de erro avisa que não temos uma função say_my_name de aridade 1 (say_my_name/1) e sugestiona a outra que criamos no exemplo anterior say_my_name/1. Para fazer esse teste passar, precisamos criar uma nova função say_my_name que suporte receber apenas um argumento.
Diferente de algumas linguagem de programação, Elixir suporte multiplas definições de uma mesma função.
Vamos criar essa nova função
lib/person.ex
defmodulePersondo# ...defsay_my_name(first_name) do"Seu primeiro nome é #{first_name}"endend
Rodando o teste agora, você terá um relatório de sucesso.
Quando chamamos uma função que tem mais de uma definição ela irá começar da primeira definição a que esta mais ao topo do aqruivo para baixo, parando na primeira oportunidade.