Saltar al contenido

El core en Rust, y lo que cuesta

La segunda mitad de la tesis: por qué un lenguaje sin recolector al otro lado del puente, qué compra de verdad más allá del eslogan de la seguridad de memoria, y una estimación honesta de la curva de aprendizaje.

Lo que el eslogan dice, y lo que omite

«Seguridad de memoria sin recolector de basura» es cierto y merece una lectura cuidadosa en este contexto concreto.

Un core de Tauri típico lee ficheros, habla con SQLite, hace peticiones HTTP, lanza algún proceso y responde comandos. Ese código, escrito en C, tendría riesgo real de desbordamientos y punteros colgantes. Escrito en Go, en C# o en TypeScript, no: esos lenguajes también son seguros en memoria, por otra vía. Así que la seguridad de memoria no distingue a Rust de sus alternativas realistas en este campo; distingue a los lenguajes con gestión automática de los que no la tienen.

Lo que sí distingue a Rust de Go, de C# y de TypeScript es otra cosa: consigue esa seguridad sin recolector, y eso tiene dos consecuencias que sí se notan aquí. La primera es el tamaño: sin runtime que empaquetar, el binario es más pequeño, y en un framework cuyo argumento entero es no enviar cosas grandes, eso es coherente. La segunda es la previsibilidad: no hay pausas, no hay un pico de memoria que el recolector todavía no ha devuelto, no hay que razonar sobre cuándo se libera algo.

Lo que Rust compra de verdad, en este puente

Tres cosas, y las tres se cobran en la fase III.

Un tipo que no se puede construir en un estado inválido. El enum de Rust lleva datos en cada variante y el compilador exige tratarlas todas. Eso permite que un mensaje que cruza la frontera esté modelado en el tipo y no en la documentación: si el comando puede devolver un error de red, uno de permisos o uno de formato, eso está en la firma, y el que llama no puede ignorarlo.

Rust
// La forma del error es parte del contrato, no una nota en el README.#[derive(thiserror::Error, Debug)]enum RunnerError {    #[error("no se encontró el ejecutable: {0}")]    NotFound(String),    #[error("el proceso excedió el tiempo límite")]    Timeout,    #[error("error de entrada/salida: {0}")]    Io(#[from] std::io::Error),}

Un Result que hay que abrir. En Rust un error no se propaga solo: o lo tratas, o lo reenvías explícitamente con ?. Un comando que puede fallar lo dice en su tipo, y quien lo escribe no puede olvidarlo. En un puente IPC, donde el otro lado es JavaScript y no tiene forma de saber qué puede salir mal, esa disciplina es exactamente lo que hace que el nivel 18 sea posible.

Un solo punto de verdad para los tipos. Esta es la ventaja más práctica y la que más se agradece: como los structs de Rust describen con precisión la forma de los datos, se pueden generar desde ellos los tipos de TypeScript del otro lado. No hay dos definiciones que mantener sincronizadas: hay una, y la otra se deriva. Ese es el nivel 19, y es donde Rust deja de ser un peaje y empieza a devolver.

La curva, sin adornos

Rust es difícil y decir lo contrario es un flaco favor. Pero «difícil» es demasiado vago para planificar, así que conviene partirlo en tres tramos según cuándo hace falta cada cosa.

La estimación realista para alguien con experiencia en otro lenguaje y sin prisa: el primer tramo son un par de semanas de práctica, no un trimestre. Lo que cuesta no es la sintaxis sino desaprender el hábito de compartir referencias mutables sin pensar, y eso se paga peleando con el compilador hasta que el modelo encaja.

El track de Rust de este centro de estudios son cincuenta y dos niveles, y no hace falta ninguno completo para empezar aquí: con sus fases de fundamentos y de tipos ya se puede escribir un core decente.

Lo que no compensa fingir

Dos avisos que valen más que un capítulo de motivación:

Un core mal escrito en Rust es peor que uno bien escrito en Go. Si el equipo va a pelear con el compilador seis meses y a resolver cada bloqueo con un clone() y un unwrap(), el resultado no tiene ninguna de las ventajas del lenguaje y sí todos sus costes. Wails existe, es bueno, y el nivel 2.3 explica cuándo es la respuesta.

El tiempo de compilación es un coste diario. Rust compila despacio. En un proyecto de escritorio de tamaño medio, cada cambio en el core cuesta segundos o decenas de segundos antes de verlo. El frontend recarga en caliente y el core no. Es una fricción real que conviene conocer antes de firmar, y hay técnicas para reducirla que la fase II menciona.