Intentemos presentar argumentos en contra de Rust

Recientemente le铆 un art铆culo que criticaba a Rust. Aunque hab铆a muchas cosas correctas al respecto, no me gust贸, demasiado es muy controvertido all铆. En general, no puedo recomendar leer ning煤n art铆culo que critique a Rust. Esto no es bueno, porque es importante discutir las deficiencias, y la difamaci贸n de las cr铆ticas ineptas y de baja calidad, desafortunadamente, hace que se ignoren los argumentos realmente buenos.



Entonces, intentar茅 argumentar en contra de Rust.



No toda la programaci贸n es sistem谩tica



Rust es un lenguaje de programaci贸n de sistemas. Proporciona un control preciso sobre la composici贸n de datos y el comportamiento de ejecuci贸n de c贸digo en tiempo de ejecuci贸n para obtener el m谩ximo rendimiento y flexibilidad. A diferencia de otros lenguajes de programaci贸n de sistemas, tambi茅n proporciona seguridad en la memoria: los programas con errores terminan de una manera bien definida, lo que evita un comportamiento indefinido (potencialmente peligroso).



En la mayor铆a de los casos, sin embargo, no se requiere un rendimiento absoluto o control sobre los recursos de hardware. Para estas situaciones, los lenguajes administrados modernos como Kotlin o Go brindan una velocidad decente, un rendimiento envidiable y seguridad de la memoria mediante el uso de un recolector de basura administrado din谩micamente.



Complejidad



El tiempo del programador es caro y, en el caso de Rust, tienes que dedicar mucho tiempo a aprender el idioma en s铆. La comunidad ha trabajado duro para crear materiales did谩cticos de alta calidad, pero el idioma es muy extenso. Incluso si le resulta rentable reescribir el proyecto en Rust, aprender el idioma en s铆 puede resultar demasiado caro.



El precio por un control mejorado es la maldici贸n de la elecci贸n:



struct Foo     { bar: Bar         }
struct Foo<'a> { bar: &'a Bar     }
struct Foo<'a> { bar: &'a mut Bar }
struct Foo     { bar: Box<Bar>    }
struct Foo     { bar: Rc<Bar>     }
struct Foo     { bar: Arc<Bar>    }


En Kotlin, escribes una clase Foo(val bar: Bar)y comienzas a resolver un problema. En Rust, tienes que hacer elecciones, a veces importantes, con una sintaxis especial.



Toda esta complejidad se debe a una raz贸n: no sabemos c贸mo crear un lenguaje de bajo nivel m谩s simple y seguro para la memoria. Pero no todas las tareas necesitan un lenguaje de bajo nivel.



Vea tambi茅n la presentaci贸n Por qu茅 C ++ se mantiene a flote cuando el Vaza se hundi贸 .



Tiempo de compilaci贸n



El tiempo de compilaci贸n es un factor universal. Si un programa en alg煤n idioma se ejecuta lentamente, pero este idioma permite una compilaci贸n r谩pida, entonces el programador tendr谩 m谩s tiempo para optimizar y acelerar el inicio del programa.



En el dilema de los gen茅ricos, Rust eligi贸 deliberadamente compiladores lentos. Esto tiene cierto sentido (el tiempo de ejecuci贸n se est谩 acelerando mucho), pero tendr谩s que luchar duro por tiempos de construcci贸n razonables en proyectos m谩s grandes.



rustcimplementa probablemente el algoritmo de compilaci贸n incremental m谩s avanzado en los compiladores de producci贸n, pero es un poco como luchar contra el modelo de compilaci贸n incorporado del lenguaje.



A diferencia de C ++, el ensamblaje de Rust no est谩 paralelo al l铆mite, el n煤mero de procesos en paralelo est谩 limitado por la longitud de la ruta cr铆tica en el gr谩fico de dependencia. La diferencia se notar谩 si tiene m谩s de 40 n煤cleos para compilar.



En Rust, tampoco hay an谩logos para el idioma pimpl , por lo que cambiar la caja requiere volver a compilar (y no solo vincular) todas sus dependencias inversas.



Madurez



Definitivamente, cinco a帽os es poco tiempo, por lo que Rust es un idioma joven. Si bien el futuro parece brillante, es m谩s probable que dentro de diez a帽os estemos programando en C en lugar de en Rust (ver el efecto Lindy ). Si ha estado escribiendo software durante d茅cadas, entonces deber铆a considerar seriamente los riesgos de elegir nuevas tecnolog铆as (aunque elegir Java sobre Cobol para el software bancario en los a帽os 90 result贸 ser la elecci贸n correcta en retrospectiva).



Solo hay una implementaci贸n completa de Rust, el compilador rustc . Implementaci贸n de mrustc alternativa m谩s avanzadaomite deliberadamente muchos controles de seguridad est谩ticos. Actualmente, rustc solo admite un backend listo para producci贸n, LLVM. En consecuencia, el soporte para arquitecturas de procesador es m谩s limitado aqu铆 que C, que tiene una implementaci贸n GCC, as铆 como soporte para varios compiladores propietarios espec铆ficos del proveedor.



Finalmente, Rust no tiene especificaciones oficiales. La especificaci贸n actual est谩 incompleta y no documenta algunos detalles menores de implementaci贸n.



Alternativas



Adem谩s de Rust, existen otros lenguajes para la programaci贸n de sistemas, incluidos C, C ++ y Ada.



C ++ moderno proporciona herramientas y pautas para mejorar la seguridad. 隆Incluso hay una propuesta de seguridad de por vida para objetos estilo Rust! A diferencia de Rust, el uso de estas herramientas no garantiza que no haya problemas de seguridad en la memoria. Pero si ya es compatible con una gran cantidad de c贸digo C ++, tiene sentido verificarlo, quiz谩s seguir las recomendaciones y usar desinfectantes ayudar谩 a resolver problemas de seguridad. 隆Esto es dif铆cil, pero claramente m谩s f谩cil que reescribir todo el c贸digo en otro idioma!



Si est谩 utilizando C, puede aplicar m茅todos formales para demostrarsin comportamiento indefinido, o simplemente probar todo a fondo .



Ada es segura para la memoria a menos que use memoria din谩mica (nunca llame free).



Rust es un lenguaje interesante de costo a seguridad, 隆pero lejos de ser el 煤nico!



Set de herramientas



Las herramientas de Rust no son perfectas. El conjunto de herramientas b谩sico, el compilador y el sistema de compilaci贸n ( cargo ) a menudo se citan como los mejores de su clase.



Pero, por ejemplo, algunas herramientas relacionadas con el tiempo de ejecuci贸n (principalmente para la creaci贸n de perfiles de pila) simplemente faltan; 隆es dif铆cil pensar en el tiempo de ejecuci贸n si la herramienta simplemente no est谩 ah铆! Adem谩s, la compatibilidad con IDE tambi茅n est谩 muy por debajo del nivel de confiabilidad de Java. La refactorizaci贸n compleja automatizada de un programa con millones de l铆neas simplemente no es posible en Rust.



Integraci贸n



Independientemente de lo que prometa Rust, el mundo de la programaci贸n de sistemas de hoy habla C y C ++. Rust no intenta imitar estos lenguajes intencionalmente, no usa clases de estilo C ++ o C ABI.



Esto significa que se deben construir puentes entre los mundos. La integraci贸n no ser谩 perfecta, insegura, no siempre rentable y requiere sincronizaci贸n entre idiomas. Si bien la integraci贸n funciona en algunos lugares y el conjunto de herramientas est谩 convergiendo, existen obst谩culos ocasionales en el camino debido a la complejidad general.



Un problema espec铆fico es que la visi贸n del mundo demasiado confiada de Cargo (ideal para proyectos puros de Rust) puede dificultar la integraci贸n con sistemas de construcci贸n m谩s grandes.



Actuaci贸n



"Usar LLVM" no es una soluci贸n 煤nica para todos los problemas de rendimiento. Si bien no conozco puntos de referencia que comparen el rendimiento de C ++ y Rust en general, no es dif铆cil pensar en tareas en las que Rust sea inferior a C ++.



Probablemente el mayor problema es que la sem谩ntica de movimiento de Rust se basa memcpyen valores ( a nivel de c贸digo de m谩quina). Por otro lado, la sem谩ntica de C ++ utiliza referencias especiales de las que se pueden tomar datos (punteros a nivel de c贸digo de m谩quina). En teor铆a, el compilador deber铆a ver la cadena de copias; en la pr谩ctica, este no suele ser el caso: # 57077 . Un problema relacionado es la falta de asignaci贸n de nuevos datos: Rust a veces necesita copiar bytes hacia / desde la pila, mientras que C ++ puede crear un objeto en su lugar.



Curiosamente, el Rust ABI predeterminado (que sacrific贸 la estabilidad por la eficiencia) a veces funciona peor que C: # 26494 .



Finalmente, mientras que en teor铆a el c贸digo Rust deber铆a ser m谩s eficiente debido a la informaci贸n mucho m谩s rica sobre los alias, habilitar optimizaciones relacionadas con alias causa errores LLVM y compilaci贸n incorrecta: # 54878 .



Pero, nuevamente, estos son ejemplos raros, a veces la comparaci贸n es en la otra direcci贸n. Por ejemplo, en BoxRust no hay problemas de rendimiento, que tienen en std::unique_ptr.



Un problema potencialmente mayor es que Rust, con sus definiciones gen茅ricas, es menos expresivo que C ++. As铆 que algunos trucos de f贸rmulas C ++ para alto rendimiento no se puede expresar en Rust con una buena sintaxis.



Valor inseguro



Quiz谩s la idea sea unsafea煤n m谩s importante para Rust que la propiedad y los pr茅stamos. Al separar todas las operaciones peligrosas en bloques unsafey funciones e insistir en proporcionarles una interfaz segura de nivel superior, es posible crear un sistema que simult谩neamente:



  1. confiable (el unsafec贸digo no verificado no puede causar un comportamiento indefinido),

  2. modular (se pueden probar diferentes bloques inseguros por separado).


Es bastante obvio que este es el caso: el c贸digo Rust fuzzing encuentra p谩nico, pero no desbordamientos de b煤fer.



Pero las perspectivas te贸ricas no son tan brillantes.



En primer lugar , no existe una definici贸n del modelo de memoria de Rust, por lo que es imposible verificar formalmente si un bloque inseguro dado es v谩lido o no. Existe una definici贸n no oficial de "cosas que rustc hace o en las que puede confiar" y se est谩 trabajando en un verificador de tiempo de ejecuci贸n , pero el modelo real no est谩 claro. Por lo tanto, en alg煤n lugar, puede haber alg煤n c贸digo inseguro que funcione bien hoy, pero se declarar谩 inv谩lido ma帽ana y se interrumpir谩 en una nueva optimizaci贸n del compilador en un a帽o.



En segundo lugar, se cree que los bloques inseguros no son realmente modulares. Los bloques inseguros lo suficientemente fuertes pueden, de hecho, extender el lenguaje. Estas dos extensiones no hacen nada malo de forma aislada entre s铆, pero conducen a un comportamiento indefinido cuando se usan al mismo tiempo: consulte Equivalencia observable y C贸digo inseguro.



Finalmente, hay errores obvios en el compilador .



Aqu铆 hay algunos temas que he omitido deliberadamente:



  • Econom铆a ("m谩s dif铆cil de encontrar programadores de Rust"): creo que la secci贸n "Madurez" captura la esencia de esta pregunta, que no se limita al problema del huevo y la gallina.

  • Dependencias ("stdlib es demasiado peque帽o / demasiadas dependencias en todas partes"): dado lo bueno que son Cargo y las partes relevantes del lenguaje, personalmente no veo esto como un problema.

  • Enlace din谩mico ("Rust deber铆a tener un ABI estable"): no creo que sea un argumento s贸lido. La monomorfizaci贸n es fundamentalmente incompatible con la vinculaci贸n din谩mica, y si realmente lo necesita, existe un C ABI. Realmente creo que las cosas se pueden mejorar aqu铆, pero es poco probable que estemos hablando de cambios espec铆ficos en Rust .


Tema de discusi贸n en / r / rust .



All Articles