3 pontos por GN⁺ 2025-11-01 | 1 comentários | Compartilhar no WhatsApp
  • John Carmack compartilhou sua visão pessoal sobre o uso de variáveis mutáveis (mutable variables)
  • Mencionou que, ao usar Python, acabou relaxando o princípio de “atribuição única” (single assignment), e que precisa se policiar quanto a isso
  • Enfatizou que, exceto pelos cálculos iterativos em loops, deve-se evitar reatribuir ou atualizar variáveis
  • Se todas as etapas intermediárias de cálculo forem mantidas, isso ajuda na depuração e evita problemas em que um valor anterior é usado sem querer ao mover blocos de código
  • Explicou que, em C/C++, é um bom hábito declarar quase todas as variáveis como const no momento da inicialização
  • Por fim, destacou que “gostaria que mutable fosse uma palavra-chave”, expressando o desejo de que a imutabilidade fosse o padrão

1 comentários

 
GN⁺ 2025-11-01
Comentários do Hacker News
  • Depois de usar Clojure por 2 anos, percebi como é realmente difícil explicar para outros desenvolvedores a clareza que a imutabilidade traz
    Quem está acostumado a pensar em termos de produzir efeitos por meio de mudanças de estado tem dificuldade de entender isso antes de experimentar na prática

    • Alterar variáveis cria uma dependência de ordem implícita
      Por exemplo, se você escreve x = 7; x = x + 3; x = x / 2, trocar a ordem não gera erro, mas muda o resultado
      Já quando se usam novas variáveis como x1, x2, uma ordem incorreta causa erro e deixa o problema evidente
      No fim, atribuição única (single assignment) é uma forma de expressar explicitamente essa dependência
    • Tive uma experiência parecida com Scheme
      Mesmo explicando a colegas que nunca tinham usado uma linguagem funcional o quanto um modo de pensar centrado em funções é fácil de testar e limpo, isso não fazia muito sentido para eles
      Em Python é difícil escrever em estilo funcional de um jeito agradável de ler, e JS parece melhor nisso
      No fim, só desenvolvedores curiosos acabam tentando linguagens como Clojure
    • Quando dados imutáveis e funções puras são o padrão, uma função pode ser tratada completamente como uma caixa-preta
      A função não precisa conhecer o estado externo, e o exterior também não precisa conhecer o interior da função
      Mesmo sem conhecer o estado total do programa, dá para testar ou depurar uma função específica de forma isolada
    • Colocar imutabilidade e mutabilidade simplesmente como opostas é uma forma de evitar a complexidade
      É interessante ver a comunidade Haskell acabar tentando reinventar mutabilidade dentro do sistema de tipos
      O ponto central é controlar os efeitos colaterais com o menor custo possível
    • Clojure foi a linguagem mais influente que já aprendi
      Haskell tinha uma barreira de entrada alta por causa do sistema de tipos, e F# era conciliador demais, então eu acabava programando com sintaxe de C#
      Graças à homoiconicity de Clojure e às suas estruturas de dados poderosas, a ideia de “trabalhar com valores” finalmente ficou clara para mim
      Eu não usaria profissionalmente, mas com certeza recomendaria para quem nunca teve experiência com linguagem funcional ou Lisp
  • Eu gostaria que as variáveis fossem imutáveis por padrão e que tudo fosse expressão (expression)
    Mas a realidade é que, como desenvolvedor de Clojure, estou sofrendo com a invasão do Python

    • Também sou desenvolvedor Python, mas só uso Clojure em projetos pessoais
      Agora estou sofrendo com a invasão do TypeScript, então entendo bem
    • Depois de aprender Rust, percebi que uma linguagem não precisa ser puramente funcional para que tudo seja expressão
      Essa abordagem é realmente útil para limitar o escopo das mudanças
    • Clojure é sempre mais rápido que Python, o que já consola
    • Você é apenas alguém que usa Clojure, não precisa se definir como “programador de Clojure”
      Não há necessidade de entrar em guerras tribais entre linguagens
      Na era do aumento de produtividade, essas fronteiras não fazem sentido
      Recomendo o texto Don’t Call Yourself a Programmer
  • Tento minimizar a reatribuição de variáveis, mas às vezes uso shadowing de variáveis
    Gosto de padrões como result = result.process() por serem concisos

    • Talvez seja por ser um exemplo abstrato, mas na maioria dos casos dá para dar um nome claro a cada etapa
    • Esse tipo de padrão pode causar bugs de segurança
      Por exemplo, se process() for uma função de validação, pode ficar ambíguo em que momento aquele valor foi processado
      Por isso, é melhor distinguir claramente os estados pelos nomes
    • Em estilo funcional, isso pode ser resolvido com encadeamento de funções, sem variáveis intermediárias
      Ex.: result = x |> foo |> bar |> baz ou (-> x foo bar baz)
    • result.process()? Mas afinal, que result e que process são esses?”
      Quem ler esse código depois vai ficar confuso
    • Se já é um resultado (result), processá-lo (process) de novo é logicamente estranho
  • O próprio termo “variável (variable)” sempre me incomoda
    Se é imutável, por que chamar de variável?

    • A variável não muda durante a execução, mas pode ter valores diferentes a cada chamada
      Em Rust, ela só pode ser alterada se isso for explicitado com mut
      Já em C, para criar uma constante é preciso usar o pré-processador, o que é confuso
    • O parâmetro x de uma função recebe valores diferentes a cada chamada, então ele mesmo é um valor que varia
      Mesmo sem reatribuição, ainda pode ser chamado de variável
    • Também em matemática, variável é um símbolo que aponta para um valor arbitrário, não para um objeto específico
      A programação herdou esse conceito diretamente
    • No fim, é variável porque seu valor pode mudar entre execuções
      Uma constante (constant) tem o mesmo valor em todas as execuções
      Veja Variable (mathematics)
    • “Variável” é usada não no sentido de mudar ao longo do tempo, mas de variar conforme o contexto
  • Seria ótimo se a IDE mostrasse visualmente se uma variável foi alterada
    Por exemplo, destacando levemente as variáveis modificadas

    • No IntelliJ, variáveis reatribuídas ficam sublinhadas, e ao passar o mouse aparece a dica “Reassigned local variable”
      Usar final sempre que possível torna o código mais fácil de ler e manter
    • Ainda assim, acho melhor um opt-in explícito do que inferência automática
      A IDE deveria avisar, e a alteração só ser permitida quando realmente necessária
      Como na discussão do Rich Hickey sobre set vs list, é preciso escolher estruturas que expressem claramente o significado
    • O Swift detecta quando uma variável foi alterada pelo compilador e, se a mutação for desnecessária, sugere trocá-la por uma constante
    • As IDEs da JetBrains já têm recurso para encontrar os pontos de leitura/escrita de variáveis
    • Se alguém criasse um linter para isso, “mutalator” seria um bom nome
  • Já participei de um projeto em que a imutabilidade foi aplicada de forma rigorosa por causa da segurança de threads
    Isso deixou o código mais fácil de ler e tornou mais simples rastrear o que pode mudar
    Desde então virei um grande fã de imutabilidade

    • Nesse caso, eu realmente recomendaria experimentar Rust
  • Depois de trabalhar em uma grande base de código em Haskell e voltar para C, fiquei pensando como seria bom se imutabilidade fosse o padrão
    const não é suficiente

    • Em C, na prática, o que existe não é mutação direta, mas apenas reatribuição de valor
      Para mutar é preciso usar ponteiros, e em C++ até uma chamada de função pode alterar argumentos, o que fica opaco
    • Fico curioso para saber se o padrão do Rust já oferece uma imutabilidade segura o bastante
  • Concordo com a ideia de que “quase todas as variáveis deveriam ser declaradas como const”
    Faz sentido mencionar Rust aqui

  • Imagino uma sintaxe em que o padrão seja imutável, e mutable só seja permitido dentro de um bloco específico
    Por exemplo, como um bloco with em Python

    with mutable(x, items):
        x = 3
        items.append(4)
    

    Ao sair do bloco, tudo voltaria a ser imutável

    • Isso é, na prática, o conceito de mutable borrow
      Basta olhar o borrow checker do Rust para ver como esse conceito é complexo
    • Sem verificação de borrow, uma referência poderia continuar existindo fora do bloco e ainda ser alterada
  • Existe a frase “State is the enemy
    Quanto mais estado existe, mais as condições a testar crescem exponencialmente
    A imutabilidade é uma forma de evitar essa explosão de estados