10 puntos por GN⁺ 2024-12-29 | 3 comentarios | Compartir por WhatsApp

#9512 - Reescríbelo en Rust

  • El shell Fish fue reescrito en Rust. Ya no queda nada de código C++ y está hecho casi al 100% en Rust puro
  • Hace unos 2 años se abrió el PR (#9512) para migrar Fish de C++ a Rust
  • Fish ya había pasado antes de C a C++, pero el cambio a Rust fue un proyecto mucho más grande

Problemas en C++

  • Diferencias de herramientas y compiladores: las herramientas de C++ no son buenas, y adoptar estándares modernos de C++ genera complejidad para empaquetadores y contribuidores.
  • Seguridad en hilos: la ejecución interna de comandos en Fish actualmente es serial, y para agregar un prompt asíncrono o autocompletado no bloqueante se necesita procesamiento en paralelo.
  • Complejidad del lenguaje: los archivos de encabezado, las plantillas y el manejo de cadenas en C++ son complejos y poco seguros.
  • Comunidad: C++ no logra atraer a muchos contribuidores.
  • Problemas de dependencias: hubo molestias por la inestabilidad y los problemas de compilación de ciertas bibliotecas C (curses).

Por qué eligieron Rust

  • Diversión e interés: Fish es un proyecto hobby, así que necesitaba un lenguaje divertido e interesante. Rust resulta más atractivo para quienes contribuyen.
  • Excelentes herramientas: con rustup se puede instalar fácilmente el compilador, y los mensajes de error son claros.
  • Ergonomía: ofrece un sistema use explícito y funciones seguras como Option y Result.
  • Buen diseño del lenguaje: el sistema de punteros y opciones de Rust es mucho más seguro que el de C++.
  • Soporte para paralelismo: Send y Sync en Rust permiten procesamiento paralelo seguro.
  • Gestión de dependencias: es fácil agregar soporte para formatos externos como YAML y JSON.

Soporte de plataformas

  • Se soportan la mayoría de las plataformas principales (macOS, Linux, BSD, etc.), y el soporte nativo para Windows no es un objetivo.
  • Fish es un shell centrado en UNIX, por lo que se enfoca más en APIs y lenguajes de scripting de UNIX que en el entorno Windows.

Proceso de portabilidad

  • Fish pasó gradualmente de C++ a Rust con un enfoque de "el pez de Theseus", migrando los componentes uno por uno y permitiendo que C++ y Rust coexistieran.
    • Barco de Teseo (Ship of Theseus): “Si se reemplazan todas las tablas de madera de un barco por unas nuevas, ¿sigue siendo el mismo barco?”
  • Uso de FFI: se utilizó autocxx para generar bindings entre C++ y Rust, portando un componente a la vez.
  • Portabilidad a gran escala: ciertas partes (por ejemplo, el manejo de I/O) se migraron por separado para reducir el código FFI complejo.
  • Mejora de herramientas: durante el proceso se personalizó autocxx para resolver problemas de interoperabilidad entre Rust y C++.

Línea de tiempo

  • Enero de 2023: se abrió el PR inicial
  • Enero de 2024: se eliminó por completo el código C++
  • Diciembre de 2024: lanzamiento de la beta de Fish 4.0

Fricciones con Rust

  • Problemas de portabilidad: el enfoque de Rust con #[cfg(...)] es ineficiente para manejar diferencias de sistema a bajo nivel.
  • Localización: las cadenas de formato de Rust se verifican en tiempo de compilación, pero no se pueden traducir.
  • Tiempo de compilación: usar LTO y la compilación release predeterminada puede alargar el tiempo de build.
  • Durante el proceso de portabilidad se cometieron algunos errores, pero la mayoría se resolvió con facilidad.

Logros principales

  • Eliminación de curses: la base de datos terminfo fue reemplazada por un crate de Rust, resolviendo el estado global y los problemas de compilación.
  • Ejecutable único: ahora es posible generar un binario de Fish con todas las dependencias incluidas.
    • Esto permite que el paquete de Fish sea auto-instalable, facilitando su uso para los usuarios.
  • Mejora de rendimiento: se optimizó el uso de memoria y se facilitó agregar nuevas funciones.

Limitaciones

  • No se pudo eliminar por completo CMake
  • Fin del soporte para Cygwin: no existe un target de Rust
  • En Windows sigue siendo posible ejecutarlo solo a través de WSL

Presente y futuro

  • Fish 4.0 fue portado con éxito y su rendimiento mejoró.
  • Fish sigue siendo un shell UNIX, y el cambio a Rust permite agregar nuevas funciones.
  • Ahora tiene una base de código completamente migrada a Rust, más fácil de mantener y de ampliar con nuevas funciones que antes. Se podrán aprovechar las ventajas de Rust para agregar nuevas capacidades.
  • Esta transición se completó con éxito y tuvo un impacto positivo tanto para quienes contribuyen como para los usuarios.

3 comentarios

 
annyeong 2024-12-30

Me gusta la usabilidad de fish, pero por problemas de compatibilidad y rendimiento uso zsh configurado para que se parezca lo más posible a fish. Tengo curiosidad por ver cómo será el nuevo fish 👀

 
GN⁺ 2024-12-29
Comentarios en Hacker News
  • Felicitaciones al equipo de Fish; los detalles del proyecto son interesantes. Me pregunto si es el proyecto más grande que ha migrado por completo de C++ a Rust. Podría ofrecer lecciones útiles para otros proyectos

    • Fish no se lanzó como un programa híbrido de C++ y Rust. La etapa final de pruebas no se había completado
    • Hay quienes no entienden la motivación de agregar capacidades de Rust a C++, pero esto podría ser un buen caso de estudio
    • Existe la opinión de que sería bueno poder escribir código nuevo en Rust dentro de una base de código en C++
  • La principal queja sobre Rust es el soporte para detección por versión. La detección por capacidades es mejor para distribuciones, navegadores web y compiladores

    • La detección por versión/nombre es la razón por la que Chrome e IE fingen ser Mozilla, y por la que Clang finge ser GCC. La detección por capacidades no provoca esos problemas
  • Uno de los objetivos del port era eliminar CMake, pero fracasó. Cargo es excelente para compilar, pero es simple para instalar. Fish tiene muchos scripts y documentación, así que no encaja con el caso de uso de Cargo

    • Se prefiere que otra herramienta implemente este caso de uso, en lugar de expandir Cargo para cubrirlo
  • Hace algunos años cambié de bash a zsh y quedé satisfecho, pero al probar fish en una computadora nueva, zsh me pareció engorroso y anticuado. Recomiendo usar fish durante unas semanas

  • Es una lástima que no se soporte Cygwin. Ojalá Rust llegue a soportar Cygwin como objetivo de compilación

  • Impresiona el esfuerzo del equipo de Fish, y genera expectativa ver cómo evolucionará el proyecto

  • Me pregunto qué tan fácil será para los mantenedores de paquetes distribuir Rust-fish siguiendo las directrices de Debian

  • Felicitaciones al equipo de Fish; la mejor shell ha mejorado aún más. Se propone actualizar el eslogan del proyecto a "Finally, a shell for the 00s!"

  • Después de cambiar de zsh a Fish, la configuración se volvió más simple, y como Fish funciona tal como esperaba, no pienso volver a cambiar

  • La macro cfg! se compila como true/false, por lo que el código dentro de un guard if debe poder compilar. Si se compila sin my_feature, puede fallar

  • Fish usa hilos para el autocompletado y el resaltado de sintaxis, y existe un proyecto de largo plazo para agregar concurrencia al lenguaje