- El autor, que ha usado C++ durante más de 20 años, presenta cómo redescubrió las ventajas de Rust a través de una charla de Matt Godbolt
- En C++, los errores por confusión de tipos no siempre son detectados correctamente por el compilador, pero Rust los bloquea con fuerza en tiempo de compilación
- Rust tiene un diseño ventajoso no solo para la seguridad de memoria, sino también para prevenir el mal uso de APIs
- En particular, incluso al procesar entradas en tiempo de ejecución, Rust obliga a manejar los errores de forma explícita, reduciendo los riesgos
- En última instancia, este es un caso que muestra cómo el diseño de un lenguaje puede ser una herramienta poderosa para prevenir errores de los desarrolladores
Introducción
- La charla de Matt Godbolt, "Correct by Construction", pone el foco en los problemas de diseño de APIs en C++, algo que también encaja con la filosofía de Rust
- Esta charla es un buen material de introducción para entender las fortalezas de Rust
What's in a type — los límites de C++
- Una firma de función como
void sendOrder(const char *symbol, bool buy, int quantity, double price) es muy propensa a errores
- Si solo se usan tipos básicos como
bool, int y double, aunque se pase un tipo equivocado, el compilador no advierte nada
- Un alias de tipo como
using Price = double no ofrece una distinción real entre tipos
- Si se crean
Quantity y Price usando clases y constructores explicit, el compilador puede detectar algunos errores, pero:
- Los valores negativos siguen estando permitidos, y eso solo se vuelve un problema en tiempo de ejecución
- Con
static_assert y plantillas se puede forzar una verificación en tiempo de compilación
- Pero aun así, conversiones en tiempo de ejecución como
atoi pueden provocar desbordamiento de enteros, y el compilador no puede detectarlo
¿Cómo es diferente Rust?
- Incluso con una definición de función equivalente, Rust marca claramente como error en compilación cualquier incompatibilidad de tipos
- Definir nuevos tipos como
struct Price(pub f64); struct Quantity(pub u64); también es sencillo, y bloquear entradas negativas funciona de forma natural
- Conversiones de cadenas en tiempo de ejecución como
"string".parse::<u64>() también requieren manejo explícito de errores
- Si se fuerza el desempaquetado del valor con
.expect(), se produce un fallo en tiempo de ejecución, pero se subraya que eso sigue siendo mejor que un error silencioso en C++
Conclusión
- Rust protege a los desarrolladores no solo con estabilidad de memoria, sino también mediante prevención del mal uso de APIs, verificaciones en tiempo de compilación y un sistema de tipos claro
- Muestra cómo el poder del diseño de lenguajes puede prevenir errores de los desarrolladores antes de que ocurran
- Quienes empiezan con Rust pueden tener dificultades al pelear con el borrow checker, pero eso se supera con el tiempo
- Aunque C++ ha evolucionado mucho históricamente, sigue quedando claro que todavía le cuesta ofrecer la seguridad fundamental y la claridad que Rust sí brinda
Referencias
4 comentarios
Parece que la mayoría de las cosas que se mencionan como desventajas de C++ se mantienen principalmente por la compatibilidad con C.
¿Se podría cambiar para poder desarrollar dejando de lado la compatibilidad con C?
Habría sido mejor si no hubiera ofrecido
unsafe.lenguaje base = Rust
Opiniones de Hacker News
La mayor ventaja de Rust es el tipo
Result, que unifica la forma de propagar errores. Resulta atractivo no tener que preocuparse por excepciones ni por distintas formas de devolver errores?y a la interfaz funcional deResult, el manejo de errores es entretenido y fácil de trabajarHay muchas quejas sobre C++. En particular, el problema es que hay que recordar muchas reglas y, si se falla aunque sea en una, el código puede volverse vulnerable
El código C++ que se escribe actualmente se parece a Rust. Usa tipado explícito y fuerte, además de una gestión clara de los tiempos de vida
El problema de las conversiones implícitas en C++ es más un problema de las bibliotecas que del lenguaje
En Rust es incómodo usar structs de Args/Options porque no hay argumentos con nombre ni tuplas con nombre
La opción
-Wconversionpuede detectar ciertos problemas de conversión, pero no aplica en todos los casosLo mejor de Rust es que no tiene conversiones numéricas implícitas. En C++, es mejor no usar
atoiy utilizar las funciones de conversión de la STLAún no existen en Rust ni en Golang funciones similares a las restricciones de SQL o a los tipos personalizados y validadores de pydantic
Si te interesa el podcast de programación de Matt y Ben Rady, "Two's Complement", vale la pena escucharlo