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]
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)
o resultado vai ser:
iex> Enum.at([:a, :b, :c, :d, :e],3)
:d
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
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
Ruby adiciona requintes de crueldade permitindo índices negativos.
Top comments (10)
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
comlists:nth
, pois como já podemos ver pelos nomes, são completamente diferentes.A descrição de
Enum.at
é:"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
é:"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.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 deEnum
, 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çõesdelete_at
,pop_at
e provavelmente outras.Nada que me impeça de amar Elixir.
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).
Contar começando de 0 pra mim, que vejo do ponto de vista de um programador iniciante, é um erro. Mas é um erro bem pequeno, um "errinho".
O "hardware não sabe o que são matrizes. Arrays costumavam começar com 1. C decidiu fazer array igual a um espaço na memória e, portanto, a indexação por zero fazia sentido."
"Porque o mal que C impingiu ao mundo não se enraizou em todos os lugares? Fortran, LISP e Smalltalk começaram com 1. New Jersey começou com 0."
Mark Guzdial
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:
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)
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".
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)
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.
"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.
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 😅
Sim, índice negativo deve ser uma ferramenta fantástica para programadores avançados.