DEV Community

Elixir UTFPR
Elixir UTFPR

Posted on

Um errinho em Elixir

Elixir não é uma linguagem perfeita, claro.

O "erro" que vou comentar aqui está na função Enum.at/3.

Deixa explicar melhor. Se eu tenho uma lista com 5 elementos:

[:a, :b, :c, :d, :e]
Enter fullscreen mode Exit fullscreen mode

e eu perguntar a você qual é o terceiro elemento, obviamente você vai me responder que é o :c.

Mas se eu usar Enum.at/3 da seguinte forma:

Enum.at([:a, :b, :c, :d, :e],3)
Enter fullscreen mode Exit fullscreen mode

o resultado vai ser:

iex> Enum.at([:a, :b, :c, :d, :e],3)
:d
Enter fullscreen mode Exit fullscreen mode

Interessante é que é um "erro" (coloco entre aspas por não ser um erro de verdade mas sim uma escolha que eu acredito ser errada) que não veio do Erlang:

> lists:nth(3, [a, b, c, d, e]).
c
Enter fullscreen mode Exit fullscreen mode

O Maxsuel Maccari explicou neste tweet a razão provável deste erro estar em Elixir. Ruby faz isso. Veja aqui e abaixo:

arr = [1, 2, 3, 4, 5, 6]
arr[2]    #=> 3
arr[100]  #=> nil
arr[-3]   #=> 4
Enter fullscreen mode Exit fullscreen mode

Ruby adiciona requintes de crueldade permitindo índices negativos.

Discussion (10)

Collapse
wldomiciano profile image
Wellington Domiciano

Eu entendi que por erro vc quis dizer "decisão errada que não veio de Erlang", mas não dá para concluir isso comparando Enum.at com lists:nth, pois como já podemos ver pelos nomes, são completamente diferentes.

A descrição de Enum.at é:

Finds the element at the given index (zero-based).

"Encontra o elemento no índice fornecido".

Se eu escrevo Enum.at([:a, :b, :c, :d, :e],3) eu não estou dizendo "me dá o terceiro elemento", estou dizendo "me dá o elemento que está no índice 3", e já que índice começa no 0, é esperado que o resultado seja :d.

Já a descrição de lists:nth é:

Returns the Nth element of List.

"Retorna o enésimo elemento da lista".

Se eu escrevo lists:nth(3, [a, b, c, d, e]) estou dizendo que quero o terceiro elemento.


Ou seja, Enum.at faz exatamente o que o nome sugere e a documentação descreve.

Collapse
elixir_utfpr profile image
Elixir UTFPR Author • Edited

Eu chamaria apenas de "decisão errada". O fato de ter vindo de Erlang ou não pouco importa.

Erlang não tem um Enum, certo? O mais próximo de Enum, mas que é conceitualmente diferente, é lists.

Não faz diferença no que eu considero "erro" o fato da documentação da função Enum.at descrever exatamente o que ela faz. Não é um bug.

O "erro" (sempre entre aspas) se repete em Elixir no módulo List, nas funções delete_at, pop_at e provavelmente outras.

Nada que me impeça de amar Elixir.

Collapse
rhamorim profile image
Roberto Amorim

Acesso a arrays baseado em zero não é erro - é um legado da forma como se indexa em C. É uma consequência da forma como "aritmética de ponteiros" funciona, e que é - pra quem trabalha com C e outras linguagens mais "perto do metal" - a maneira mais "natural" de pensar nesse tipo de indexação.

Em outras palavras: não é um erro, é uma escolha. Pode-se até argumentar que seja uma escolha ruim (ou que seja anacrônica ou contraproducente numa linguagem mais "abstrata"), mas é uma escolha que tem razão de existir e vários argumentos a favor (e contra).

Thread Thread
elixir_utfpr profile image
Elixir UTFPR Author • Edited
Collapse
wlsf profile image
Willian Frantz

Curioso esse jeito de pensar, mas eu não vejo como um erro em nenhum ponto.

Desde o período de faculdade, sempre gostei de acreditar que lidar com indexes deveria ser assim mesmo, pois se parar pra pensar a gente considera o index 0 como sendo nosso ponto de partida, e a partir dele eu consigo pular pra qualquer index que eu quiser somente determinando quantas casas eu quero pular, e inclusive consigo ter noção da distância.

Ex:

arr = [1, 2, 3, 4, 5, 6]
Enter fullscreen mode Exit fullscreen mode

Se eu parto do index 0 onde o valor é 1 arr[0] == 1, então eu consigo claramente saber que pra chegar no valor 3, eu preciso pular exatas 2 casas pra direita. arr[2] == 3

E também consigo determinar que o valor 3 está a exatas 2 casas de distância do valor 1 (que se encontra no index 0)

Collapse
elixir_utfpr profile image
Elixir UTFPR Author

Mas o ponto de partida dos seres humanos não devs é um. Se eu começo a contar laranjas, eu começo de 1. Qualquer explicação que não leve isto em consideração, está apenas justificando um "erro".

Collapse
wlsf profile image
Willian Frantz • Edited

Mas "contar laranjas" me parece uma coisa bem diferente de posicionar essas laranjas em índices. Dispor elas de uma forma que você possa calcular a distância entre uma laranja até outra.

ex: Tendo em vista que você tem 4 laranjas, e você já está posicionado na primeira laranja, quantas laranjas você precisa pular pra conseguir alcançar a laranja numero 4? Seriam 3 pulos.

Você consegue contar elementos em Elixir normalmente sem precisar levar em consideração o índice em que estes elementos estão posicionados.

Enum.count(list)

Thread Thread
elixir_utfpr profile image
Elixir UTFPR Author
  1. Estou pensando em contar no sentido de 1, 2, 3,..., não de calcular o total de elementos de uma lista. Você está certo, claro. Eu que misturei.

  2. "Dispor elas de uma forma que você possa calcular a distância entre uma laranja até outra." Este é meu ponto: se eu tenho uma função que me dá um elemento de uma coleção ordenada, e eu quero o terceiro elemento, a função deveria receber 3 para me dar o terceiro elemento. Isto é o principal, não o cálculo de distâncias entre os elementos. Lembrando sempre que o meu ponto de vista é: o que vai facilitar para iniciantes?

Mas, como já disse em outros comentários, isto é um "errinho" mínimo. Elixir é quase perfeita.

Collapse
lucassperez profile image
Lucas Perez • Edited

Sinceramente, índices negativos pra arrays são uma mão na roda. Se você quiser pegar o último elemento, pode fazer array[-1]. Inclusive isso nem é específico de Ruby.

Já em Elixir, os índices quase nem importam, uma vez que acessar um elemento por índice numa lista ligada é uma tarefa provavelmente pouco produtiva. Além disso, existem linguagens que indexam a partir do 1 e uma decisão assim normalmente gera discórdia e estranhamento 😅

Collapse
elixir_utfpr profile image
Elixir UTFPR Author

Sim, índice negativo deve ser uma ferramenta fantástica para programadores avançados.