3 puntos por GN⁺ 2025-11-01 | 1 comentarios | Compartir por WhatsApp
  • John Carmack compartió su opinión personal sobre el uso de variables mutables
  • Mencionó que, al usar Python, ha tendido a descuidar el principio de single assignment, y que debe cuidarse de eso él mismo
  • Enfatizó que, salvo en los cálculos repetitivos de los bucles, se debe evitar reasignar o actualizar variables
  • Si se conservan todos los pasos intermedios del cálculo, eso ayuda durante la depuración y puede evitar problemas en los que se use accidentalmente un valor anterior al mover bloques de código
  • Explicó que, en C/C++, es una buena práctica declarar casi todas las variables como const en el momento de su inicialización
  • Finalmente, subrayó que "ojalá mutable fuera una palabra clave", expresando su deseo de que la inmutabilidad sea el valor predeterminado

1 comentarios

 
GN⁺ 2025-11-01
Opinión en Hacker News
  • Después de usar Clojure durante 2 años, sentí que era realmente difícil explicarles a otros desarrolladores la claridad que aporta la inmutabilidad
    A quienes están acostumbrados a pensar en términos de producir efectos mediante cambios de estado les cuesta entenderlo antes de experimentarlo directamente

    • Cambiar variables crea dependencias de orden implícitas
      Por ejemplo, si escribes x = 7; x = x + 3; x = x / 2, cambiar el orden no produce un error, pero sí un resultado distinto
      En cambio, si usas variables nuevas como x1, x2, un orden incorrecto provoca un error y hace que el problema quede claro
      En última instancia, la asignación única (single assignment) es una forma de expresar explícitamente esas dependencias
    • Yo también tuve una experiencia similar con Scheme
      Aunque les explicaba a colegas que nunca habían usado un lenguaje funcional lo fácil de probar y limpio que es pensar en funciones, no terminaba de hacerles clic
      En Python es difícil escribir un estilo funcional que sea agradable de leer, y JS me parece mejor en ese sentido
      Al final, solo los desarrolladores curiosos terminan probando lenguajes como Clojure
    • Si tomas los datos inmutables y las funciones puras como base, puedes tratar una función completamente como una caja negra
      La función no necesita conocer el estado externo, y el exterior tampoco necesita conocer el interior de la función
      Incluso sin conocer el estado completo del programa, puedes probar o depurar una función específica de forma independiente
    • Oponer inmutabilidad y mutabilidad como si fueran polos contrarios es evadir la complejidad
      Es interesante ver que la comunidad de Haskell termina intentando reinventar la mutabilidad dentro del sistema de tipos
      La clave es controlar los efectos secundarios con el menor costo posible
    • Clojure fue el lenguaje más influyente que he aprendido
      Haskell tenía una barrera de entrada alta por su sistema de tipos, y F# era demasiado de compromiso, así que uno terminaba programando con sintaxis de C#
      Gracias a la homoiconicidad de Clojure y a sus potentes estructuras de datos, por primera vez entendí claramente el concepto de “trabajar con valores”
      No lo usaría profesionalmente, pero sí se lo recomendaría sin dudar a cualquiera que no tenga experiencia con lenguajes funcionales o Lisp
  • Me gustaría que las variables fueran inmutables por defecto y que todo fuera una expresión (expression)
    Pero la realidad es que, como desarrollador de Clojure, sufro la invasión de Python

    • Yo también soy desarrollador de Python, pero solo uso Clojure en proyectos personales
      Ahora estoy sufriendo la invasión de TypeScript, así que lo entiendo
    • Después de aprender Rust, me di cuenta de que, aunque un lenguaje no sea puramente funcional, todo puede ser una expresión
      Esta forma de trabajar es muy útil para limitar el alcance de los cambios
    • Clojure siempre es más rápido que Python, y eso consuela
    • Tú solo eres alguien que usa Clojure; no necesitas definirte como “programador de Clojure”
      No hace falta quedar atrapado en las guerras tribales entre lenguajes
      En una era de aumento de productividad, esas fronteras no significan mucho
      Recomiendo el texto Don’t Call Yourself a Programmer
  • Intento minimizar la reasignación de variables, pero a veces uso sombreado de variables
    Prefiero patrones como result = result.process() porque son concisos

    • Tal vez sea por lo abstracto del ejemplo, pero en la mayoría de los casos puedes ponerles nombres claros a cada etapa
    • Este tipo de patrón puede provocar errores de seguridad
      Por ejemplo, si process() es una función de validación, puede volverse ambiguo en qué momento fue procesado ese valor
      Por eso es mejor distinguir claramente el estado mediante el nombre
    • En un estilo funcional, esto puede resolverse con encadenamiento de funciones sin variables intermedias
      Ejemplo: result = x |> foo |> bar |> baz o (-> x foo bar baz)
    • “¿result.process()? ¿Qué result y qué process se supone que es eso?”
      Quien lea el código después va a confundirse
    • Si ya es un resultado (result), volver a procesarlo (process) suena lógicamente extraño
  • El término “variable” en sí siempre me ha hecho ruido
    Si es inmutable, ¿por qué llamarla variable?

    • Una variable no cambia durante la ejecución, pero puede tener un valor distinto en cada llamada
      En Rust solo puede modificarse si se marca explícitamente con mut
      En cambio, en C hay que usar el preprocesador para crear constantes, lo cual resulta confuso
    • El argumento x de una función recibe un valor distinto en cada llamada, así que en sí mismo es un valor que varía
      Incluso sin reasignación, puede seguir llamándose variable
    • También en matemáticas una variable es un símbolo que apunta a un valor arbitrario, no a un objeto específico
      La programación tomó ese concepto tal cual
    • Al final, es variable porque su valor puede cambiar entre ejecuciones
      Una constante (constant) tiene el mismo valor en todas las ejecuciones
      Véase Variable (mathematics)
    • “Variable” no se usa tanto en el sentido de que cambie con el tiempo, sino de que depende del contexto
  • Estaría bien que el IDE mostrara visualmente si una variable fue modificada
    Por ejemplo, que las variables modificadas tuvieran una pequeña marca

    • En IntelliJ, las variables reasignadas aparecen subrayadas y, al pasar el cursor, muestra la pista “Reassigned local variable”
      Usar final tanto como sea posible hace que el código sea más fácil de leer y mantener
    • Pero creo que es mejor un opt-in explícito que una inferencia automática
      El IDE debería advertirlo y permitir cambios solo cuando de verdad sean necesarios
      Como en la historia de set vs list de Rich Hickey, conviene elegir estructuras que expresen el significado con claridad
    • Swift detecta en el compilador si una variable fue modificada y, si ese cambio es innecesario, sugiere convertirla en constante
    • Los IDE de JetBrains ya tienen una función para encontrar los lugares de lectura/escritura de una variable
    • Si alguien hiciera un linter para esto, “mutalator” sería un buen nombre
  • Antes trabajé en un proyecto donde se aplicó la inmutabilidad de forma estricta por seguridad de hilos
    Gracias a eso, el código se volvió más fácil de leer y de seguir en cuanto a qué podía cambiar y qué no
    Desde entonces soy un gran fan de la inmutabilidad

    • Entonces de verdad te recomendaría probar Rust
  • Después de trabajar en una gran base de código de Haskell y volver a C, me quedó la sensación de que la inmutabilidad debería ser el valor por defecto
    const no alcanza

    • En C, en realidad no puedes modificar directamente, solo reasignar valores
      Para modificar necesitas usar punteros, y en C++ una llamada a función puede cambiar argumentos, lo que vuelve todo menos transparente
    • Me pregunto si el valor por defecto de Rust ofrece una inmutabilidad lo bastante segura
  • Coincido con la idea de que “conviene declarar casi todas las variables como const”
    Vale la pena mencionar Rust

  • Imagino una sintaxis donde lo inmutable sea el valor por defecto y solo se permita mutable dentro de un bloque específico
    Por ejemplo, como un bloque with de Python

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

    Al salir del bloque, volvería a ser inmutable

    • Eso es básicamente el concepto de mutable borrow
      Basta ver el borrow checker de Rust para darse cuenta de lo complejo que es ese concepto
    • Sin verificación de borrow, una referencia podría seguir existiendo fuera del bloque y permitir cambios
  • Hay una frase: “State is the enemy
    Mientras más estado haya, más crecen exponencialmente las condiciones que hay que probar
    La inmutabilidad es una forma de evitar esa explosión de estado