Elixir v1.20: agora uma linguagem de tipos graduais
(elixir-lang.org)- Inferência de tipos e verificação gradual (gradually) de tipos agora se aplicam a todos os programas Elixir, encontrando código morto e bugs comprovados que necessariamente falhariam em tempo de execução, mesmo sem anotações de tipo
- O tipo
dynamic(), ao contrário deany()que “permite qualquer coisa”, acompanha em tempo de execução o intervalo de tipos possíveis e só relata violação quando não há sobreposição completa com os tipos permitidos - Um valor
dynamic(integer() or binary())não gera violação em chamadas com alguma sobreposição de possibilidade, como operações numéricas ou funções de string, mas gera violação em chamadas que aceitam apenas map, comoMap.fetch! dynamic()é refinado conforme a forma de uso, depurandodatapara um map no formato%{..., a: number(), b: number()}em código comodata.a + data.b- Em guards, união, interseção e negação são inferidas, usando condições como
is_list,is_integer,is_map_key,not is_map_keyetuple_sizecomo informação de tipo casee condicionais refletem a informação das cláusulas anteriores nas seguintes, realizando verificação de tipos ao tratarnilprimeiro e então restringir o valor restante parabinary(), por exemplo- Várias funções da biblioteca padrão relacionadas a tuple e map receberam tipos, ajudando a encontrar cláusulas redundantes e código morto em bases de código existentes
- No “If T: Benchmark for Type Narrowing”, passou em 12 de 13 categorias, mostrando que é possível recuperar informação de tipos precisa em código Elixir comum
- A v1.20 também voltou a melhorar o tempo de compilação em aplicações com múltiplos núcleos, e em benchmarks sintéticos a ferramenta de build do Elixir mostrou o melhor resultado entre as linguagens BEAM
- A nova opção do compilador
:module_definitionpermite escolher o modo de execução da definição de módulo entre o padrão:compiledou:interpreted, e pode ser ativada comelixirc_options: [module_definition: :interpreted]nomix.exs - A opção
:module_definitionnão afeta os arquivos.beamgravados em disco e altera apenas a forma de execução dentro dedefmodule, podendo ajudar a melhorar o tempo de compilação em projetos grandes - As novas assinaturas de tipo com tipos conjuntistas deverão ser discutidas junto com a definição de typed struct depois que forem concluídas as pesquisas sobre desempenho do sistema de tipos da v1.20, tipos recursivos, tipos parametrizados e iteração de chave-valor em map
1 comentários
Comentários no Hacker News
Pode ser experiência pessoal, mas tenho a impressão de que, se a linguagem não tinha tipos desde o início, ela nunca funciona tão bem quanto uma linguagem realmente estaticamente tipada
Trabalho como desenvolvedor profissional de Elixir há uns 10 anos e espero por tipos há muito tempo. Fico realmente feliz de ver esse começo entrando de fato agora
Dito isso, queria entender como o estado em que isso chega no v1.20 se compara ao Dialyzer sem especificações. Pelo que eu entendia, a abordagem de success typing do Dialyzer é mais próxima de “se existir ao menos uma combinação de argumentos que funcione, ele não avisa” do que de “se existir uma combinação de argumentos que possa falhar, ele avisa”; achei que o Elixir estivesse fazendo algo parecido nisso, e nunca senti que o Dialyzer fosse muito útil
Já vi alguns posts no HN sobre o sistema de tipos graduais do Elixir, mas não acompanhei em detalhe. Queria saber se alguém sabe se esse sistema de tipos graduais pode mudar a complexidade assintótica do programa em comparação com código sem tipos
Pelo que sei, a maioria dos sistemas de tipos graduais, como o do Racket, pode tornar o programa assintoticamente mais lento, com algumas exceções [1]
[1] https://doi.org/10.1145/3314221.3314627
A maioria dos sistemas de tipos graduais insere coerções quando valores atravessam a fronteira entre código tipado e não tipado. Por exemplo, verificando todos os elementos de uma lista ou encapsulando um valor em um proxy de tipo. Mas a equipe do Elixir publicou o resultado de strong arrows para obter correção sem essas verificações em tempo de execução, e o bytecode emitido pelo compilador é semanticamente idêntico ao do código sem tipos
Ironicamente, os críticos diziam que tipos eram necessários, e os fãs de Elixir diziam que não eram necessários e que o Elixir era meio mágico de algum jeito, então bugs de tipo não aconteciam. Agora colocaram tipos e eles estão encontrando bugs. Não era para não precisar disso para evitar bugs? Ainda assim, é uma boa mudança. Já usei bastante Elixir antes e gostei, mas era difícil concordar com a ausência de tipos
https://en.wiktionary.org/wiki/Goomba_fallacy
Não concordo com essa visão, mas ela é bem mais defensável do que “$LANGUAGE é mágico”
Antes do avanço da teoria de tipos conjuntivos, essa posição talvez até estivesse correta
Aí no fim acabam adicionando tipagem estática. Aconteceu com Python, JavaScript e Ruby, e deve haver mais casos
É muito bom poder atualizar o Elixir sem mudanças incompatíveis em vários projetos, e ainda ter o compilador encontrando bugs de graça. Já fiquei mal-acostumado com isso
Fico realmente feliz de ver isso. Agora está chegando mais perto do nível de “linguagem excelente”, e para mim o Elixir é o principal candidato
Se alguém souber de outra linguagem que já seja confortável de usar e continue adicionando recursos excelentes de forma estável e segura, eu agradeceria. Eu estava ficando bom em Go e depois migrei para aprender C# avançado, mas senti que o Go parou de adicionar bons recursos
No último mês fiz a trilha de Elixir do exercism.io https://exercism.org/tracks/elixir
É realmente excelente
Ah, lá vamos nós de novo. Acho que vou passar mais 1 ano aprendendo Elixir de novo
Eu gosto de tudo em Elixir, mas, mais do que qualquer outra linguagem, Elixir vive me fazendo duvidar de mim mesmo. Parece que meu cérebro não foi feito para o funcional, mas essa mudança me dá vontade de tentar de novo
O lado ruim é que não dá para dizer que o ecossistema seja muito amigável para iniciantes, e muitas vezes, ao responder perguntas, as pessoas já partem do pressuposto de que você conhece bastante a linguagem
Não se deixe enganar pelo título. A primeira metade do livro é só Elixir
Ao longo dos últimos 8 anos, sempre que precisei me reacostumar com Elixir, usei esse livro, e ele sempre funcionou bem. Nunca li até o fim
Um dos meus critérios para saber se esse tipo de livro de programação baseado em projeto/tutorial é bom é se, mesmo começando várias vezes sem chegar ao final, ele já me dá ferramentas suficientes na metade para eu ir fazer meu próprio trabalho
Mas acho que não é tanto porque meu cérebro não combina com isso, e sim pelo contraste entre o nível de experiência acumulado em linguagens imperativas e o fato de que, em um estilo puramente funcional, você está começando de novo como iniciante
Vai melhorar aos poucos. O que me fez ficar mais à vontade com programação funcional foi perceber o quanto eu gosto de compor código estilo “one-liner” de Bash, com bastante espaço. Se os dados começam em algum formato, eu despejo com um comando, penso nas etapas que os aproximam do formato desejado, passo para o próximo comando por pipe e inspeciono de novo. Continuando assim, no fim normalmente sobra uma sequência de transformações de dados que não alteram nada
Uma das razões pelas quais isso é confortável no shell é que, no dia a dia, você fica navegando pelo sistema de arquivos e vai acumulando vocabulário de comandos. Em um ambiente tipo Unix, a biblioteca de “funções” familiares cresce bastante ao longo dos anos. Em um ambiente de programação puramente funcional, você precisa fazer a mesma coisa, só que aprender o vocabulário exige um pouco mais de esforço. Os “comandos” usados com frequência passam a ser funções como
map,foldezip, em vez de grep, cat e sortMas, no fundo, a ideia é a mesma, e o encanto de montar pipelines se aplica igualmente aos dois lados. Dá para construir pedaço por pedaço e, em cada etapa do quebra-cabeça, esquecer a anterior e pensar só em como transformar os dados que estão na sua frente no próximo passo. Essa baixa exigência de contexto é revigorante e confortável
Espero que você tente e goste. Quando você consegue até apreciar o estado de ainda não saber fazer algo, é aí que finalmente começa a ficar bom nisso
Claro, só mexi por algumas tardes, mas, se eu fosse treinar meu cérebro de novo para uma linguagem funcional, acho que escolheria Gleam justamente por essa familiaridade
Às vezes um post fica sem atenção por ser vago, ou é ignorado porque tem cara de “façam meu dever de casa por mim”
Mas, pelo que vi, posts com curiosidade genuína sempre recebem resposta
Excelente. Na 1.20, parece que a compilação do nosso grande app umbrella ficou consideravelmente mais rápida
Fiquei curioso sobre como isso se compara com Gleam. Ou, agora, por que usar Elixir em vez de Gleam? Imagino que Phoenix, especialmente LiveView, seja um grande atrativo do Elixir
Não sei como está o estado atual do Gleam OTP, mas, da última vez que vi, não estava bom
Se tanto faz e o que importa para você são os tipos, então use Gleam. Mas, nesse caso, por que não usar Rust logo?
Por exemplo, no Gleam a decodificação/codificação de JSON acaba ficando verbosa. Em Rust, basta dar derive com serde; em Elixir, uma chamada de função resolve
Elixir tem um ecossistema mais maduro. Por exemplo, até dá para usar Phoenix a partir do Gleam ou usar algum outro framework de Gleam, mas a experiência não é a mesma
O grande motivo para Gleam ser mais atraente que Elixir são os tipos, e agora Elixir está diminuindo essa diferença. Também tem o fato de poder compilar para JavaScript, e no Elixir o Hologram faz algo parecido
Pessoalmente, gosto mais do sistema de tipos do Gleam e da sintaxe estilo Rust, mas, hoje, sinto que Elixir é a melhor escolha para todos os meus projetos de desenvolvimento web