2 pontos por GN⁺ 3 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • 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 de any() 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, como Map.fetch!
  • dynamic() é refinado conforme a forma de uso, depurando data para um map no formato %{..., a: number(), b: number()} em código como data.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_key e tuple_size como informação de tipo
  • case e condicionais refletem a informação das cláusulas anteriores nas seguintes, realizando verificação de tipos ao tratar nil primeiro e então restringir o valor restante para binary(), 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_definition permite escolher o modo de execução da definição de módulo entre o padrão :compiled ou :interpreted, e pode ser ativada com elixirc_options: [module_definition: :interpreted] no mix.exs
  • A opção :module_definition não afeta os arquivos .beam gravados em disco e altera apenas a forma de execução dentro de defmodule, 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

 
GN⁺ 3 시간 전
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

    • Concordo, mas há outra perspectiva: “Why are gradual static types so great?” https://www.benkuhn.net/gradual/
    • Por outro lado, o TypeScript acabou virando meu sistema de tipos favorito, porque precisa dar suporte a todo tipo de padrão bizarro que as pessoas vinham usando em uma linguagem sem tipos
  • 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

    • Fico curioso para ver o que isso vai encontrar em uma base de código Elixir de 10 anos ainda em produção
  • 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

    • O sistema de tipos graduais do Elixir não pode mudar a complexidade assintótica do programa. Por projeto, ele exclui explicitamente casts em tempo de execução nas fronteiras entre código estático e dinâmico, que são a causa da lentidão em outros sistemas de tipos graduais
      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

    • Isso é a falácia do Goomba
      https://en.wiktionary.org/wiki/Goomba_fallacy
    • Não acompanhei Elixir tão de perto especificamente, mas o que vi nas discussões do lado do Erlang era um pouco diferente. Como de qualquer forma é preciso lidar com falhas de maneira elegante, a linha de pensamento era tratar erros de tipo com os mecanismos de recuperação de falhas que já precisam existir
      Não concordo com essa visão, mas ela é bem mais defensável do que “$LANGUAGE é mágico”
    • Não posso garantir que nunca vi alguém fazer esse argumento, mas não me lembro de ter visto, e mesmo que tenha existido, deve ter sido uma minoria ínfima. O argumento contrário real geralmente era mais algo como “tipos são bons, mas têm custo, e esse custo nem sempre volta em benefício suficiente”
      Antes do avanço da teoria de tipos conjuntivos, essa posição talvez até estivesse correta
    • A mesma coisa aconteceu com JavaScript/TypeScript e Python. Às vezes, só resta deixar as pessoas pensarem o que querem pensar
    • É o ciclo da vida. Linguagens de tipagem dinâmica ganham fãs, outras pessoas dizem — com razão — que seriam muito mais úteis se tivessem tipagem estática. Os fãs levam isso para o lado pessoal e dizem que tipagem estática não é necessária. Os motivos variam: “não é útil mesmo”, “vai contra o espírito da linguagem”, “é só uma linguagem de script”, “é só usar um depurador”, “tipagem estática atrapalha a produtividade” etc.
      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

    • https://pragprog.com/titles/lhelph/functional-web-developmen...
      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
    • Passei exatamente por esse sofrimento quando tive meu primeiro contato com Haskell numa disciplina da faculdade tipo “visão geral de paradigmas de programação”. Eu já programava havia alguns anos, então foi inacreditável perceber como eu podia ser tão incapaz de fazer coisas que há muito tempo pareciam básicas
      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, fold e zip, em vez de grep, cat e sort
      Mas, 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
    • Fiquei curioso se você conhece um pouco de Rust. Eu também não tenho muita experiência com linguagens funcionais, mas Gleam me pareceu familiar por causa do lado mais parecido com Rust, então consegui focar mais nos conceitos do que na sintaxe
      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
    • Recomendo perguntar no ElixirForum. Nunca vi respostas realmente hostis por lá
      À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
    • Esse tipo de fala sempre me confunde. Um programa orientado a objetos todo embolado de estado é muito mais difícil de raciocinar para mim
  • 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

    • A diferença é se você gosta de Rust ou de Erlang. Usar Gleam parece usar Rust; usar Elixir parece usar Erlang
      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?
    • O site do Gleam já tem um material de comparação
    • Gleam não tem macros, e muitas bibliotecas de Elixir, como Phoenix e Ecto, usam macros de forma muito eficaz
      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
    • Na prática, é por causa de Phoenix e Ecto