1 pontos por GN⁺ 2025-06-04 | 1 comentários | Compartilhar no WhatsApp
  • A repetição de if err != nil em Go permaneceu por anos como uma grande insatisfação nas pesquisas com usuários, mas a equipe de Go decidiu não avançar, por enquanto, com mudanças na sintaxe de tratamento de erros
  • As propostas de check/handle em 2018, try em 2019 e ? em 2024 não conseguiram consenso suficiente; em especial, try enfrentou forte resistência por causa do fluxo de controle oculto
  • Pelo processo de propostas de Go, quando não há consenso geral, a proposta normalmente é rejeitada; mesmo entre membros seniores da equipe de Go no Google, não há unanimidade hoje sobre a melhor direção
  • Quem defende manter o estado atual entende que Go já tem uma forma funcional de tratar erros e que uma nova sintaxe geraria custos altos em estilo de código, depuração, documentação, ferramentas e código existente
  • A equipe de Go vai fechar, sem investigação adicional, propostas abertas e novas propostas que tenham como foco principal a sintaxe de tratamento de erros, e concentrar-se em outras oportunidades de melhoria até que surja uma percepção mais clara do problema

A antiga insatisfação criada por if err != nil

  • Uma das insatisfações mais duradouras em Go é a verbosidade do código de tratamento de erros
  • O padrão típico tem a seguinte forma
x, err := call()
if err != nil {
    // handle err
}
  • Em programas com muitas chamadas de API que simplesmente retornam erros, if err != nil pode dominar o restante do código
  • Na função de exemplo printSum, das 10 linhas do corpo da função, 4 linhas parecem trabalho real, incluindo chamadas, impressão e retorno, enquanto as outras 6 parecem ruído
  • Nas pesquisas anuais com usuários de Go, o tratamento de erros esteve por anos entre as principais insatisfações; por algum tempo, a ausência de generics ficou à frente, mas, depois que Go passou a dar suporte a generics, o tratamento de erros voltou ao topo das queixas

Três grandes propostas de sintaxe

  • A primeira tentativa explícita da equipe de Go começou em 2018, como parte do esforço Go 2, quando Russ Cox organizou formalmente o problema
  • O rascunho de design de Marcel van Lohuizen se baseava nos mecanismos check e handle, e também incluía uma análise de abordagens de outras linguagens e alternativas
func printSum(a, b string) error {
    handle err { return err }
    x := check strconv.Atoi(a)
    y := check strconv.Atoi(b)
    fmt.Println("result:", x + y)
    return nil
}
  • A abordagem check/handle foi considerada complexa demais e, em 2019, surgiu uma proposta try mais simples
    • A palavra-chave semelhante a check virou a função built-in try
    • A parte handle foi removida
    • Foi criada a ferramenta tryhard para converter código existente de tratamento de erros para o estilo try
    • A issue no GitHub relacionada foi debatida intensamente, com quase 900 comentários
func printSum(a, b string) error {
    // use a defer statement to augment errors before returning
    x := try(strconv.Atoi(a))
    y := try(strconv.Atoi(b))
    fmt.Println("result:", x + y)
    return nil
}
  • try afetava o fluxo de controle, retornando da função envolvente quando ocorria um erro, e o retorno poderia acontecer mesmo dentro de expressões profundamente aninhadas, o que muitos usuários acharam difícil de aceitar
  • Na época, talvez tivesse sido melhor introduzir uma nova palavra-chave; hoje é possível controlar a versão da linguagem com granularidade por meio do arquivo go.mod e de diretivas por arquivo
  • A proposta recente de Jimmy Frasche segue a direção de voltar ao design original de check/handle, tratando algumas desvantagens

Reflexões sobre o processo após try e a proposta ?

  • Após a proposta try, Russ Cox revisitou o processo de propostas na série “Thinking about the Go Proposal Process”
  • “Go Proposal Process: Large Changes” avaliou que try deveria ter sido um segundo rascunho de design, não uma proposta com cronograma de implementação
  • Nos anos seguintes, a equipe de Go não impulsionou mudanças na sintaxe de tratamento de erros, enquanto a comunidade continuou enviando propostas parecidas, interessantes, difíceis de entender ou inviáveis
  • Ian Lance Taylor criou uma umbrella issue para organizar o estado das propostas de melhoria no tratamento de erros, e também surgiu uma Go Wiki para reunir feedback e discussões relacionadas
  • “go error handling proposals”, de Sean K. H. Liao, acompanha muitas propostas de tratamento de erros ao longo dos anos
  • Com a continuidade das insatisfações, Ian Lance Taylor apresentou em 2024 uma proposta para reduzir boilerplate de tratamento de erros usando ?
    • A notação foi emprestada do ? operator de Rust
    • Em um pequeno estudo informal com usuários, a maioria dos participantes inferiu corretamente o significado do código Go usando ?
    • Também foram criados uma ferramenta para converter código Go comum para a nova sintaxe e um protótipo de compilador
func printSum(a, b string) error {
    x := strconv.Atoi(a) ?
    y := strconv.Atoi(b) ?
    fmt.Println("result:", x + y)
    return nil
}
  • Essa proposta também rapidamente recebeu muitos comentários e sugestões de ajustes detalhados baseados em preferências; Ian fechou a proposta e moveu o conteúdo para uma discussion
  • Uma versão levemente modificada obteve uma reação um pouco mais positiva, mas não alcançou apoio amplo

Por que querem parar agora

  • A equipe de Go concluiu que deve parar de tentar resolver o problema sintático do tratamento de erros no futuro previsível
  • O processo de propostas dá suporte a essa decisão
    • O objetivo do processo de propostas é chegar, em tempo adequado, a um consenso geral sobre o resultado
    • Quando não se encontra consenso geral na discussão do issue tracker, a proposta normalmente é rejeitada
    • Se não houver consenso nem um próximo passo claro, os Go architects revisam a discussão e tentam chegar a um consenso interno
  • Nenhuma proposta de tratamento de erros chegou perto de obter apoio consensual, e todas foram rejeitadas
  • Nem mesmo os membros seniores da equipe de Go no Google têm unanimidade hoje sobre a melhor direção a seguir, e não é possível avançar de forma razoável sem um consenso forte

Argumentos pela manutenção do estado atual e pela mudança

  • Há razões práticas a favor de manter o estado atual, ligadas à maturidade de Go e aos custos para o ecossistema
    • Se Go tivesse introduzido cedo um açúcar sintático dedicado para tratamento de erros, hoje haveria menos controvérsia, mas Go já tem 15 anos e possui uma forma de tratamento de erros que funciona
    • Mesmo que uma solução perfeita fosse encontrada agora, a situação poderia apenas passar a desagradar os que preferem manter o estado atual em vez dos defensores da mudança
    • Generics não precisam necessariamente ser usados diretamente pelos usuários, mas uma nova sintaxe de tratamento de erros poderia fazer o código parecer não idiomático se não fosse usada, tornando seu uso praticamente obrigatório para a maioria
    • Adicionar uma nova sintaxe também pode conflitar com a regra de design de Go de não oferecer várias formas de fazer a mesma coisa
  • O recurso de redeclaração da declaração curta de variáveis := foi introduzido para resolver um problema causado pelo tratamento de erros
    • Sem redeclaração, cada verificação de erro consecutiva exigiria nomes diferentes para err ou declarações separadas de variáveis
    • Se na época houvesse um suporte sintático melhor para tratamento de erros, a regra de redeclaração e a complexidade relacionada talvez não fossem necessárias
  • Quando os erros são devidamente enriquecidos e tratados, a proporção de repetição simples diminui
    • Nas pesquisas com usuários, há comentários recorrentes sobre a ausência de stack trace nos erros
    • É possível retornar erros enriquecidos por meio de funções auxiliares
    • Ao acrescentar informações de entrada, como em fmt.Errorf("invalid integer: %q", a), o peso relativo do boilerplate diminui
  • Recursos da biblioteca padrão também podem reduzir boilerplate no tratamento de erros
    • Isso segue uma direção semelhante à de “Errors are values”, de Rob Pike
    • Em alguns casos, cmp.Or permite lidar com vários erros de uma só vez
  • Escrever, ler e depurar são atividades diferentes
    • Escrever verificações repetitivas de erro é tedioso, mas IDEs e autocompletar com auxílio de LLM podem gerar facilmente verificações básicas de erro
    • Na leitura, a verbosidade se destaca mais, e a IDE poderia oferecer um toggle para ocultar código de tratamento de erros
    • Na depuração, já ter instruções if separadas facilita adicionar println ou definir breakpoints
    • Se o tratamento de erros ficar oculto atrás de check, try ou ?, pode ser necessário convertê-lo de volta para instruções if, e esse processo pode complicar a depuração ou introduzir bugs sutis
  • Mudanças na linguagem trazem custos não só de design e implementação, mas também de alteração de código existente, atualização de documentação e ajuste de ferramentas
    • A equipe de Go é relativamente pequena e tem muitas outras prioridades a tratar
    • Prioridades e tamanho da equipe podem mudar
  • No Google Cloud Next 2025, alguns usuários de Go encontrados pela equipe de Go disseram com força que a linguagem não deveria ser alterada para melhorar o tratamento de erros
    • Eles disseram que, ao vir de outras linguagens, a ausência de uma sintaxe dedicada de tratamento de erros em Go é o que mais chama atenção, mas que isso se torna menos importante conforme passam a escrever código Go mais idiomático
    • Essa amostra não é grande o suficiente para ser representativa, mas pode ser um grupo diferente das pessoas vistas no GitHub
  • Os argumentos a favor da mudança continuam válidos
    • A ausência de suporte melhor para tratamento de erros permanece entre as principais insatisfações nas pesquisas com usuários
    • Abordagens focadas apenas em reduzir o número de caracteres podem estar na direção errada
    • Se o tratamento básico de erros fosse tornado bem visível por meio de uma palavra-chave, ao mesmo tempo removendo o boilerplate err != nil, seria mais fácil verificar em code reviews se os erros estão sendo tratados
    • Ainda não se sabe o bastante se o núcleo do problema é apenas a verbosidade sintática ou a verbosidade do bom tratamento de erros, isto é, construir erros significativos para APIs, desenvolvedores e usuários finais

A decisão da equipe de Go

  • Até agora, nenhuma tentativa de tratar erros ganhou impulso suficiente
  • A equipe de Go entende que falta uma compreensão compartilhada do problema e que nem todos concordam sequer que exista um problema
  • No futuro previsível, não vai promover mudanças sintáticas na linguagem para tratamento de erros
  • Propostas abertas e futuras propostas que tenham como foco principal a sintaxe de tratamento de erros serão fechadas sem investigação adicional
  • A exploração e a discussão da comunidade não levaram a mudanças na sintaxe de tratamento de erros, mas resultaram em várias melhorias na linguagem Go e em seus processos

1 comentários

 
GN⁺ 2025-06-04
Opiniões no Hacker News
  • Se alguém quiser soltar de forma leviana uma sugestão do tipo “era só ter feito assim” para a equipe do Go, gostaria que antes olhasse a página da wiki linkada no texto, https://go.dev/wiki/Go2ErrorHandlingFeedback, e a busca de issues no GitHub, https://github.com/golang/go/issues?q=+is%3Aissue+label%3Aerror-handling
    O que você está prestes a propor quase certamente não é inédito, e há uma boa chance de que muitas dessas ideias já tenham sido analisadas em profundidade
    Vejo com bons olhos essa abordagem franca da equipe do Go, e ainda uso Go com prazer todos os dias no trabalho

    • O rascunho de design que serviu de base para o feedback menciona C++, Rust e Swift, mas no enorme documento de feedback linkado não encontrei abordagens usadas em Haskell/Scala/OCaml, como notação do, for-comprehension ou monadic-let
      Também não vi nada parecido em algumas páginas das issues do GitHub com mais comentários, e acho forçado supor que, por a equipe do Go ser formada por magos de design de linguagens, eles obviamente já avaliaram as soluções que as pessoas daqui jogam de forma leviana
      A equipe do Go cometeu o mesmo erro do Java, isto é, ter tipagem estática sem polimorfismo paramétrico, e a raiz desse problema de tratamento de erros também está aí; parece que eles simplesmente levantaram as mãos e não vão corrigir
    • Acho curioso que, mesmo com pessoas realmente inteligentes e experientes escrevendo aquela página e debatendo por anos, a solução ao estilo Haskell, com mônadas Maybe/Either e notação do usando operador bind, não apareça em lugar nenhum
      Pode soar grandioso e intimidador, mas é uma forma elegante e funcionalmente pura de propagar erros até onde eles possam ser tratados sem deixá-los serem esquecidos
      Para quem escreve código Haskell, isso é algo tão enraizado que é difícil entender como não havia ninguém na comunidade Go que conhecesse e gostasse dessa abordagem
      Agradeço pela página em si e pelos links, mas é desconcertante ver pessoas que se importam tanto com sua linguagem pularem uma solução tão bem estabelecida
    • Talvez já exista uma resposta em algum lugar, mas fico curioso para saber por que isso é um problema especialmente difícil em Go
      Quase todas as linguagens têm, cada uma à sua maneira, uma abordagem melhor; queria saber se é apenas uma questão de não conseguirem decidir ou de não conseguirem agradar a todos, ou se há algum motivo concreto na própria linguagem Go que faz com que as soluções de outras linguagens não se encaixem
    • Um padrão comum nas críticas ao Go é que pessoas relativamente amadoras presumem que quem cria Go entende menos de linguagens de programação do que elas
      Na prática, em quase todos os casos, eles sabem muito mais
      O amador pensa ingenuamente que a melhor linguagem é aquela em que se enfia o maior número possível de recursos, especialmente quando são recursos do seu gosto
      É parecido com alguém que acabou de começar a fazer facas olhar para uma faca de chef japonesa e achá-la insuficiente, depois imaginar que ela ficaria melhor com um cabo impresso em 3D com sulcos para os dedos, compartimento secreto, isqueiro e alto-falante Bluetooth
    • É estranho chamarem de Wiki algo que agora exige aprovação para ser editado
  • Basta criar uma lista de checkboxes, discutir e preencher cada item, e depois não remover nada a menos que se descubra um erro semântico fatal ou uma brecha de soundness
    Quando tudo estiver preenchido, implementem; e as pessoas que ficavam tagarelando se deveria ser .await, /await ou .await!() vão desaparecer de novo
    Rust funciona assim e, embora algumas issues fiquem atrasadas por mais de 10 anos, no fim os itens são preenchidos e estabilizados no nightly mais recente
    Se Go não consegue resolver um único problema que todo mundo encontra imediatamente, mesmo havendo várias propostas bem acabadas, porque não consegue escolher uma delas e fica esperando o bikeshedding parar, então o processo é uma comédia

    • Não existe essa coisa de “há várias propostas completas e perfeitas”
    • É exatamente assim que Rust ganha a reputação de ser uma linguagem feia de ler e com sintaxe inconsistente por causa de design por comitê
    • Uma linguagem de programação é um sistema projetado e precisa fazer sentido como um todo
      Não é uma coleção de recursos que simplesmente são adicionados quando atendem a uma lista de requisitos com checkboxes
    • Queria colocar um lembrete para daqui a 25 anos
      Rust terá virado uma bagunça como C++? Go continuará sendo uma linguagem atemporal, como era no lançamento?
    • É estranho dizer que “Go não consegue resolver um único problema que todo mundo encontra imediatamente”
      Na pesquisa, a porcentagem que mencionou tratamento de erros foi de 13%, e há também pessoas que preferem exatamente o jeito atual
      https://go.dev/blog/survey2024-h1-results
  • Já escrevi antes uma função Go peculiar que esperava que uma função interna retornasse um erro
    Por isso, se a função interna não retornasse um erro, a função externa tinha que retornar um erro e fazer outro processamento; se a função interna retornasse um erro, tinha que retornar nil
    Em resumo, eu precisava escrever if err == nil { // return an error }, e não if err != nil { ... }, mas, por hábito, escrevi a primeira forma comum e levei um bom tempo para depurar
    Foi porque eu fiquei tão insensível a if err != nil que meu cérebro nem considerou a possibilidade de que aquela construção não deveria estar ali
    Por isso acho que expressões comuns precisam de açúcar sintático. Se a diferença entre o extremamente comum if err != nil e o raro if err == nil fosse mais evidente, isso teria ajudado de verdade

    • Sempre que escrevo if err == nil, coloco um comentário // inverted para chamar atenção
      Seria bom se isso fosse tratado no nível da linguagem, mas compartilho ao menos como uma forma de tornar mais visível
    • Claro que if fruit != "Apple" { ... } também pode criar exatamente a mesma situação
      Fico curioso se existe uma solução geral para melhorar isso, e ver isso como um problema exclusivo de tratamento de erros parece meio fora de foco
      Não há nada especial ou único em erros; eles são apenas um estado como qualquer outro
    • Isso, na verdade, vira um argumento contra mudar a sintaxe
      Se surgir um padrão comum if err == nil { return ... }, desta vez ele é que vai ficar espalhado pelo código
      A solução atual é boa, e parece que quem não gosta dela são principalmente pessoas que acabaram de começar em Go ou ainda são iniciantes
      Ao meu redor, as pessoas gostam do tratamento de erros “verboso”, explícito, claro e fácil de ler
    • Fazendo o papel de advogado do diabo, IDEs e fontes poderiam, apenas no modo de sintaxe de Go, destacar if err != nil como se fosse um único símbolo de ligadura pequeno, ou renderizá-lo esmaecido em segundo plano
      Assim, uma forma que difira exatamente dessa string, como if err == nil, ficaria mais chamativa
    • Bom ponto. Parece que isso também poderia ser resolvido no editor com uma notação dobrada, tipo if err … {
  • Gosto do tratamento explícito de erros em Go
    Uma função sempre tem sucesso, ou pode ter sucesso ou falhar. Funções que sempre têm sucesso são simples; quando uma função que pode falhar falha, o código externo não pode continuar em estado de falha, então precisa lidar com isso
    É aqui que as linguagens se dividem. Muitas linguagens lançam exceções, propagando-as até alguém capturá-las explicitamente, e fornecem algum tipo de stack trace
    Em Go, gosto do fato de que, ao escrever código, você sempre tem escolhas a fazer: ignorar o erro e prosseguir (foo, _ := doSomething()), retornar cedo sem informação significativa (return nil, err), retornar cedo adicionando contexto útil, ou interpretar o erro recebido e ramificar
    Por exemplo, se uma linha a ser modificada não for encontrada no banco de dados, a camada de serviço pode retornar um erro de not found e a API responder 404, ou uma função de exclusão idempotente pode interpretar not found como sucesso
    Em Go 2 ou em outra linguagem, eu gostaria de ter, em vez de tuplas potencialmente nil, um tipo Result no estilo Rust/Swift e tipos de erro mais bem tipados e enumeráveis, em vez de usar sempre error diretamente
    No entanto, adicionar Result por cima do retorno idiomático por tupla do Go 1 criaria várias formas de fazer a mesma coisa, gerando confusão e divisão; por isso combina mais com Go 2 ou com uma nova linguagem

    • Pela minha experiência, a política de tratamento de erros deve ser delegada ao chamador
      Camadas mais baixas da stack em geral não sabem o que fazer, então não deveriam tratar o erro
      A política de tratar um erro acaba facilmente virando a política de envolver o erro e retorná-lo de volta para cima na stack, o que dá bastante trabalho braçal
    • “Se uma função falha, é preciso lidar com essa falha” é exatamente onde Go falha
      Go permite ignorar erros completamente, e isso pode acabar levando a crashes
      Acho meio difícil entender como alguém consegue identificar corretamente o requisito para criar software robusto e ainda assim gostar da forma de tratamento de erros de Go
    • Gostaria que a sintaxe do borgo[1] virasse diretamente a linguagem Go 2. Sonhar é permitido
      [1]: https://borgo-lang.github.io/ | https://github.com/borgo-lang/borgo
    • Nesse ritmo, Go2 parece um laboratório de ideias que nunca será lançado
    • Eu perguntaria: melhor em comparação com o quê?
      Todas as linguagens funcionais, muitas linguagens modernas como Rust, e até Java com checked exceptions oferecem isso
      Em uma linguagem com generics, dá para replicar em grande parte o “tratamento de erros” à moda Go, e provavelmente produzir um código melhor
      Se a resposta for JavaScript ou Python, esse é mesmo um padrão comum de comparação
  • Para Go, esta é a decisão certa. Quando conheci Go, eu não gostava do tratamento de erros, mas hoje passei a gostar bastante
    A virada veio por dois motivos. Li o texto https://go.dev/blog/errors-are-values e assimilei de verdade a perspectiva de que “erros são valores”; com base nisso, também criei um pacote relativamente popular, https://github.com/stytchauth/sqx
    Além disso, fui me acostumando aos poucos a usar panic(err) em estados inválidos que realmente não fazem sentido
    Não há motivo para forçar o código pai a tratar todos os estados absurdos com os quais ele nem tem noção de como lidar, e um ou dois panics bem posicionados podem eliminar centenas de verificações de erro em uma base de código
    Por exemplo, dá para pensar em algo como verificar se há um logger padrão dentro de ctx

    • É uma pena. Nenhum dos dois argumentos apresentados tem relação com o quão ruim é o tratamento de erros em Go, e torná-lo melhor não pioraria nada
      Pelo contrário, é bem provável que melhore
    • Até PHP tem tratamento de erros melhor, graças aos níveis de erro e ao operador @, que suprime erros no ponto de chamada
      bash também tem -e
    • Eu também gosto do jeito de Go. Aceito ter mais linhas de código se isso me der mais certeza sobre o que está acontecendo
      Quando comecei a usar C# antigo, achava inteligente entender o fluxo de try/catch/finally, using, aninhamento, o que acontece se der erro no catch, o que acontece se der erro no finally
      Hoje prefiro não ter que pensar nessas coisas
    • Erros como tipos soma no estilo Rust também são valores
  • Não gosto da forma como este texto diz que o principal problema do tratamento de erros em Go é que a sintaxe é verbosa demais. Isso não me incomoda muito
    O mais importante é que erros podem ser descartados silenciosamente ou ignorados por engano, que o resultado de uma chamada de função não é um valor e, portanto, não pode ser facilmente armazenado ou passado adiante, e que errors.Is é necessário, sendo todo esse erro “aninhado” um mecanismo estranho de runtime que não combina bem com o sistema de tipos
    Fazer switch sobre erros também é difícil, a biblioteca padrão usa valores sentinel, e a interação com generics não é boa, o que torna necessários pacotes como errgroup
    Esqueci mais alguma coisa?

    • 90% do tempo trabalhando profissionalmente com Go é inventar casos de teste à força para cobrir, com cobertura de instruções, cada ramo de retorno de erro
      Em uma linguagem com exceções, ninguém faria isso
    • Não acho que em nenhum ponto este texto afirme que “o principal problema é a sintaxe ser verbosa demais”
      Decidiu-se não fazer novas tentativas de mudar a sintaxe de tratamento de erros no futuro previsível, e isso abre espaço de atenção para olhar outros problemas, sejam eles de erros ou de outros temas
    • É preciso lembrar que Go levou um tempo enorme até oferecer algum tipo de generics
      A evolução de Go é glacialmente lenta e, para muita gente, isso é uma feature, não um bug
    • Concordo 100%. Os dois são Googlers, e é uma pena ficar decepcionado mais uma vez com a equipe de Go
    • Concordo com o ponto 1, mas isso pode ser mitigado em certa medida com ferramentas de desenvolvimento como errcheck: https://github.com/kisielk/errcheck?tab=readme-ov-file
  • Acho engraçada a explicação de que “a opinião da pesquisa de que erros não têm stack trace pode ser resolvida fazendo uma função auxiliar criar e retornar um erro enriquecido”
    É divertido chamar fornecer manualmente um stack trace de “tratamento de erros”, como em if err != nil { return fmt.Errorf("invalid integer: %q", a) }
    Pela definição da equipe de Go, exceções acabam tratando erros automaticamente. Claro, nas linguagens exceto C++

    • Acho engraçado as pessoas olharem para um stack trace que ocupa a tela inteira e dizerem que ele é claro e útil
      Pode até ser, mas você realmente precisa de tudo isso? E o custo de logs?
      Acho muito melhor um erro encapsulado de uma linha que corta o ruído de frameworks e do runtime
      Quando bem encapsulado, também é muito fácil de pesquisar e, em geral, permite rastrear com mais eficácia do que um stack trace
      Usando Go em tempo integral há mais de 10 anos, nunca precisei do ruído verboso de funções de runtime ou da pilha de chamadas
  • Do ponto de vista de um desenvolvedor Elixir, isso parece loucura
    Em Erlang/Elixir, isso normalmente se resolve fazendo a função retornar uma tupla {:ok, result} ou {:error, description_or_struct}
    Com a instrução with do Elixir, dá para concentrar o tratamento de erros na parte de baixo, o que melhora muito a legibilidade
    Go poderia adicionar algo equivalente a uma cláusula with, para continuar executando funções enquanto o erro for nil e ter uma cláusula de tratamento de erro no final

    • Com base apenas nas evidências disponíveis, parece não haver nenhuma chance de Go adotar uma instrução with
      É interessante como Go adia por muito tempo estruturas básicas e claramente valiosas, como generics, tratamento de erros e gerenciamento de pacotes, por causa da falta de consenso da comunidade
      Generics levaram 13 anos após a abertura do código; 16 anos depois, ainda não há tratamento de erros; e o gerenciamento de pacotes levou cerca de 9 anos
      Deliberação tem valor, mas lançamento também tem. As pessoas que escrevem 900 comentários no GitHub acabarão continuando a usar Go, e é bem provável que colocar algo na linguagem fosse melhor do que continuar adiando
    • O próprio retorno múltiplo de Go me parece estranho
      Uma função com vários tipos de retorno não permite fazer nada além de atribuir a variáveis
    • Usuários de Haskell e fãs de Rust tratam tipos soma como se fossem deles; as pessoas leem seus comentários e textos, acreditam neles e acabam evitando tipos soma porque não querem cair na assustadora toca do coelho Hindley-Milner
      Mas em Erlang e Elixir eles são uma forma totalmente idiomática, sem nenhum peso
      Na verdade, eles são até muito mais poderosos do que na família ML, porque ali os tipos soma são abertos
  • Não acompanhei essa discussão em detalhes, mas não entendo por que não adotam simplesmente o jeito do Rust
    Depois que Go ganhou generics, esse também é o padrão que eu acabo acrescentando logo de cara
    No texto linkado, só vejo a explicação de que “Rust não tem nada equivalente a handle, e a conveniência do operador ? pode levar as pessoas a omitirem o tratamento adequado”
    Mas não entendo por que algo ser conveniente significaria ignorar erros
    Metade do problema do jeito do Go é que ele não força nada em relação ao resultado e só força a verificação de erro no mínimo possível
    x, err := strconv.Atoi("123"); fmt.Println("result:", x)declared and not used: err, mas depois de uma segunda conversão, mesmo sem verificar err, isso pode rodar sem você perceber o problema por causa do valor zero padrão de y, que é 0
    Mesmo que você deixe vazio como if err != nil { }, compila e roda, e não dá para saber que algo deu errado
    Se o valor de retorno for um Result, você é obrigado a tomar uma decisão. Mesmo que alguém use ! de qualquer jeito ou suba o erro comodamente com ? sem tratar o caso de erro, então vamos proibir panic também?

    • Go não tem tipos soma, então não pode ter Result
      E, por causa daquela obsessão estranha de que todo tipo precisa ter um valor zero definido, também não consegue adicionar tipos soma
    • Entendo isso como: se ? for fácil de usar, ninguém mais vai encapsular erros
      É uma lógica muito suspeita
      Para começo de conversa, basta projetar ? de modo que ele incentive o encapsulamento de erros
    • É porque não está claro qual seria exatamente a forma equivalente ao levar o estilo do Rust para Go
      Por exemplo, como deveria ser, em Go, o equivalente ao From do Rust?
    • ? tem baixa visibilidade e esconde uma ramificação de fluxo de controle dentro de uma única instrução ou expressão
      Esse também é um dos motivos pelos quais Go não tem operador ternário e optou por instruções if em que cada ramo fica em uma linha separada
      Também não é fácil colocar breakpoint, e ele incentiva mais a simplesmente propagar o erro para cima do que a enriquecê-lo ou tratá-lo
    • Eu achava que := era declaração e atribuição em uma única instrução, mas, na 5ª linha do exemplo, err não está sendo declarado de novo, com o novo err sombreando o err existente?
      Se for isso, como a nova variável err não foi usada, acho que deveria falhar com declared and not used: err
      Ou, se a variável já existe, := simplesmente se comporta como uma atribuição normal?
  • Dizer que “o fato de o erro não ter stack trace pode ser resolvido fazendo uma função auxiliar criar e retornar um erro enriquecido” é otimista demais em relação à realidade
    Linguagens que têm stack trace dão isso de graça, mas em Go é preciso implementar toda vez
    Você pode ser uma pessoa desenvolvedora disciplinada que sempre acrescenta detalhes, mas nem todo mundo da equipe terá a mesma disciplina
    A melhor coisa de um stack trace é que ele fornece o caminho de chamadas até o erro
    Quando ocorre um erro em um método chamado de vários lugares, o stack trace permite saber imediatamente por qual caminho ele chegou ali
    Passei muitos anos fazendo algo parecido com sysadmin/SRE e resolvendo muitos problemas; quando havia stack trace, problemas fáceis terminavam em 1 ou 2 minutos porque a causa era óbvia
    Em Go, se alguém não enriquece o erro ou reutiliza a mesma mensagem de erro, até problemas fáceis viram trabalho de dedução e acabam levando mais tempo