#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
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 👀
Fish, el shell interactivo amigable
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
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
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
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 guardifdebe poder compilar. Si se compila sinmy_feature, puede fallarFish usa hilos para el autocompletado y el resaltado de sintaxis, y existe un proyecto de largo plazo para agregar concurrencia al lenguaje