13 puntos por GN⁺ 2025-10-17 | 2 comentarios | Compartir por WhatsApp
  • El proyecto Rust for Linux está impulsando funciones clave del lenguaje necesarias para el desarrollo del kernel, al mismo tiempo que contribuye a la evolución del propio Rust
  • Field Projection, inicialización en sitio (In-place Initialization) y Arbitrary Self Types son los tres elementos principales
  • Estas funciones permiten expresar de forma más natural en Rust estructuras propias del kernel, como smart pointers, memoria fijada (Pin) y RCU
  • El equipo de Rust prioriza la solidez del diseño, por lo que el desarrollo avanza lentamente, pero gracias al objetivo claro del kernel de Linux aumenta la concentración de esfuerzos
  • Se espera que estos cambios también impacten al ecosistema de Rust fuera del kernel, con una gran ayuda para el manejo de smart pointers y la simplificación del código

Mejoras del lenguaje Rust y el papel del kernel de Linux

  • La razón por la que el desarrollo de nuevas funciones en Rust es lento es la cautela para no fijar malos diseños en el lenguaje y el problema de la “alineación de la atención”
    • Como el proyecto Rust es operado por voluntarios, si no hay personas concentradas en una función específica, el desarrollo se retrasa
  • Como Rust for Linux es un tema que entusiasma a mucha gente, ayuda a concentrar esfuerzos en varias funciones clave necesarias para el kernel
  • El co-líder del equipo del lenguaje Rust, Tyler Mandry, presentó en Kangrejos 2025 las próximas funciones del lenguaje y mencionó que el proyecto del kernel de Linux ha actuado como catalizador para la evolución de Rust
    • Funciones principales: Field Projection, inicialización en sitio (in-place) y Arbitrary self types
    • El desarrollo del kernel presentó con claridad casos de uso reales y requisitos técnicos, lo que ayudó a concretar la dirección del diseño del lenguaje Rust
    • La máxima prioridad es la estandarización de funciones inestables (unstable) que ya se usan en los bindings del kernel

Field Projection

  • Es una función para extraer el puntero de un campo específico desde un puntero a una estructura; busca generalizar en Rust la expresión de C &(r->field)
  • Antes solo era posible con referencias (&) y punteros (*mut), pero había limitaciones con smart pointers definidos por el usuario
  • Rust for Linux está impulsando su extensión para que el acceso a campos con la misma sintaxis sea posible en todos los tipos de punteros
  • En particular, al trabajar con el tipo Pin (estructuras que no pueden moverse), se diseña para que al proyectar un campo se convierta automáticamente en Pin<&mut Field> o &mut Field
  • Si esta función se implementa, será posible soportar de forma segura el patrón RCU (Read-Copy-Update) en Rust, permitiendo acceso a datos de alto rendimiento incluso sin lock
  • Actualmente se está discutiendo en el tracking issue de GitHub, con el objetivo de estabilizarlo antes de Debian 14 (2027)

Arbitrary Self Types

  • Es una función que permite definir métodos que acepten smart pointers
  • Antes solo se soportaba la forma fn method(&self), pero ahora también será posible algo como fn method(self: Pin<&mut MyStruct>)
  • En el kernel es una función esencial porque se usan varios wrappers de punteros, como Arc, Pin y Mutex
  • Durante la implementación hubo problemas de conflicto con el trait Deref, pero se está resolviendo con la introducción del nuevo trait Receiver
  • Receiver cumple la función de indicar que un puntero puede usarse como un tipo Self arbitrario
  • En el desarrollo del kernel, esto permite mantener concisas las llamadas en cadenas de punteros
  • Ding está verificando la compatibilidad con paquetes existentes de Rust usando la herramienta Crater, y mencionó la posibilidad de estabilizarlo dentro de un año

In-place Initialization

  • Es una función que da soporte a nivel de lenguaje a la macro pin_init!() que ya se usa en el kernel
  • Permite inicializar directamente en memoria un objeto sin moverlo después de crearlo, lo que resulta útil para estructuras Pin, Future y traits dyn
  • Se están discutiendo en paralelo tres propuestas
    • Enfoque con la keyword init: aprovecha el trait existente PinInit con la mínima adición sintáctica posible
    • Enfoque con referencia &out: agrega una referencia solo de escritura, similar a un out pointer en C, con soporte para inicialización por campo
    • Enfoque de optimización estilo C++: los objetos que se moverán inmediatamente al heap se crean directamente en el heap desde el inicio
  • Al final, el plan es probar tanto PinInit como el enfoque de out-reference para validar su usabilidad real
  • Se espera que, si esta función se adopta, contribuya a simplificar la estructura no solo del kernel, sino también del código asíncrono en Rust en general

Impacto de Rust for Linux en Rust

  • El kernel de Linux está funcionando como un banco de pruebas realista para la evolución del lenguaje Rust
  • Las tres funciones surgieron de requisitos propios del kernel, como smart pointers, memoria fijada y estructuras de concurrencia, pero
    al final también beneficiarán a los desarrolladores de Rust en general
  • Estos cambios son valorados como un ejemplo de círculo virtuoso entre el desarrollo del kernel y el desarrollo del lenguaje Rust

2 comentarios

 
GN⁺ 2025-10-17
Opiniones de Hacker News
  • Me tomó algo de tiempo leer y entender el documento RFC sobre la función de lightweight clones de Rust. Al principio me pareció una función bastante interesante, pero al final me volvió a quedar claro que Rust es un lenguaje complicado de aprender. Desde la perspectiva de alguien como yo, que no ha aprendido bien Rust ni C++, da la impresión de que es como si todos los conceptos y funciones de C++ moderno estuvieran combinados con elementos de Haskell. Aun así, ver que la gente construye muchas cosas útiles con Rust me hace pensar que hay algo realmente valioso ahí. Así que creo que pronto volveré a intentar usar Rust en serio. Enlace al RFC relacionado

    • Según mi experiencia, C++ es muchísimo más complejo que Rust. Por ejemplo, solo en inicialización hay como 8 formas, hay 5 categorías de valores como xvalues, tampoco hay consistencia en formateo y convenciones de nombres, están la rule of 5, el manejo de excepciones, tener que revisar siempre this != other al hacer move assignment, perfect forwarding, SFINAE, el problema de los sustitutos de traits y un montón de complejidades más. Para usar bien C++ también hay que aprender las convenciones que se han construido sobre el estándar para poder programar de forma segura y rápida, y muchas técnicas como el manejo de excepciones chocan entre sí o te obligan a tomar caminos poco ideales

    • En la comunidad de Rust cada vez hay un ambiente más negativo hacia esta propuesta de lightweight clones. La razón es que resulta demasiado compleja. Incluso en la documentación oficial de Rust sobre la dirección del diseño, la complejidad aparece como el mayor obstáculo. No es que toda propuesta para Rust tenga que ser necesariamente simple, pero lightweight clone solo haría un poco más fácil algo que ya se puede hacer, y si la gente no lo entiende con facilidad, entonces eso sí es un problema

    • Rust se ve enorme desde lejos, pero cuando de verdad programas con él uno se acostumbra rápido. Por ejemplo, al principio no entendía nada del concepto de lifetime, así que programaba solo con Rc<>. Después de aprender lo básico y volver a estudiar lifetimes, me resultó mucho más fácil. De hecho, la mayoría de los usuarios nunca va a tener que preocuparse por funciones como lightweight clones

    • Comparado con C es muy complejo, pero comparado con C++ es muchísimo más simple. Casi no hace falta estar buscando documentación o manuales de referencia para entender el código. Rust está en un punto muy acertado: “no es tan complejo como para que se te caiga el pelo, pero tampoco tan simple como para que el código termine siendo complicado”. Además, por defecto el código tiende a tener correctness

    • La complejidad de Rust también hace que sea menos fácil usarlo mal por accidente que en C++. Y si usas clippy, este te sugiere automáticamente transformaciones hacia código más idiomatic, así que aunque no conozcas funciones nuevas como lightweight clones, igual te las puede proponer. La mayoría se puede aplicar fácilmente solo con la opción --fix de clippy. Esa parte es decisively distinta de C++, donde se van acumulando funciones que no se usan o se usan de forma excesivamente compleja, y eso produce un efecto secundario constante de acumulación de complejidad

  • Como escuché que el proyecto Rust for Linux había ayudado mucho a Rust, por curiosidad busqué archivos *.rs en el árbol del kernel. Lo que vi fue una capa de compatibilidad de API bajo la carpeta rust, y en el árbol del kernel apenas unos cuantos drivers de prueba de concepto que simplemente reescriben drivers existentes (salvo el driver inacabado de NVIDIA), así que no parece que realmente se use nada en producción. También me dio la impresión de que la reescritura en Rust de Android binder apenas sigue ahí. La impresión general es la de un pequeño proyecto experimental, y me hace preguntarme si de verdad hace falta hacer este tipo de experimento de co-desarrollo de lenguaje dentro del árbol fuente del software más importante del mundo. Más bien pensaría que sería mejor hacerlo en un sistema operativo más experimental como Redox

    • El driver de GPU para Apple silicon fue escrito en Rust, y su autor dijo que habría sido mucho más difícil desarrollarlo en C. Aún no ha sido enviado a upstream, pero explicó que “cuando desarrollas desde cero un driver de kernel complejo, normalmente surgen todo tipo de problemas como race conditions, memory leaks, use-after-free y demás; pero al escribirlo en Rust, casi no tuve ese tipo de problemas y funcionó de manera estable. Gracias a las funciones de seguridad, tengo confianza en que el driver es thread-safe y memory-safe, y el diseño mismo naturalmente se encamina hacia una buena dirección. Creo que esa es la magia de Rust”. Enlace a la experiencia del autor Y sobre la pregunta de si está bien hacer este tipo de experimentos en el árbol del kernel, se menciona que Torvalds no está de acuerdo con esa objeción

    • La opinión de que “la reescritura en Rust de Android binder apenas sigue ahí” no es cierta. El plan de este proyecto es reemplazar por completo la implementación en C. Artículo relacionado Los drivers principales para hardware Apple de la serie M también están escritos en Rust, y no son simples reescrituras ni pruebas de concepto

    • Para construir drivers complejos, primero hace falta una capa de interfaces. El proyecto RfL está haciendo justamente ese trabajo de agregar esa capa de infraestructura a upstream, y solo cuando esa base esté lista será posible escribir drivers complejos. En Red Hat están trabajando en nova, en Asahi en la GPU de Apple, y en Collabora para ARM Mali. Si tres drivers de GPU tampoco cuentan como drivers complejos, entonces ya no sé qué sí contaría como uno

    • Sobre la afirmación de que la reescritura en Rust de binder apenas sigue ahí, los mensajes de commit del árbol de Linus muestran que está en un estado muy avanzado. Rust binder ya pasa todas las pruebas de binder del Android Open Source Project, y varias apps y funciones operan sin problemas importantes. Tampoco hay problemas para arrancar ni ejecutar apps en el emulador cuttlefish ni en un Pixel 6 Pro. En este momento la funcionalidad ya es equivalente a la de binder en C, y solo faltan algunas funciones de depuración que se planea agregar pronto. Además, el proyecto Rust for Linux comenzó fuera del árbol del kernel, pero al final, para experimentar de verdad con la integración real, hay que hacerlo dentro del árbol

    • El propósito de este proyecto no es un experimento conjunto de desarrollo de lenguaje, sino usar Rust para desarrollar el kernel de Linux. Es un proyecto que empezó directamente porque desarrolladores clave querían usar Rust. Como se trata de software extremadamente importante, se está avanzando con cautela y toma tiempo construir bien las bases. Que Rust reciba beneficios colaterales de este proyecto es solo un extra

  • Vi en el artículo, en la parte sobre <i>field projection</i>, que se decidió que ahora todos los campos de structs quedarán estructuralmente pinneados, de modo que siempre salgan tipos como Pin<&mut Field>, y me di cuenta de que antes se me había pasado ese detalle. Es un tema técnicamente complejo, pero me alegra porque esta decisión resuelve un problema que venía frenando varias discusiones

  • La gente está discutiendo sobre la <i>optimización esperada inspirada en C++ para que, al crear un nuevo valor y moverlo de inmediato para asignarlo al heap, se construya directamente en el heap desde el principio</i>. Aquí el nombre “optimización” puede prestarse a malentendidos, así que hay discusión sobre cambiarle el nombre

    • Puede que yo no esté entendiendo bien la complejidad del problema, pero me parece que no se podría resolver fácilmente simplemente definiendo una calling convention adecuada. Si el struct es más grande que x o tiene un marker type, el caller podría pasar un buffer mediante outref y el callee escribiría directamente el struct ahí. Así, incluso escribiendo código normal, se podría evitar la duplicación de asignaciones en heap, y en otras situaciones también se reducirían las copias innecesarias. Como ya se le ha invertido mucho esfuerzo a este tema, más bien me da curiosidad por qué las soluciones propuestas terminan siendo más incómodas

    • Creo que, en lugar de tratar esto como una optimización interna, sería más intuitivo para todos hacerlo explícito con una función como new

    • En C++, a este tipo de semántica se le llama elision

    • Propongo nombres como coalesced heap construction o coalesced heap allocation

  • Cada vez que escucho hablar de distintas funciones de Rust, termino haciendo la broma de “por favor, lo único que no hagamos jamás es meter tokio en el kernel”. Si Rust evoluciona lo suficiente y aparece un direct composition renderer, y eso permite apps que corran a través de todo el kernel, entonces sería una situación bastante interesante

    • Implementar un async runtime dentro del kernel es realmente trivial. De hecho, la propia workqueue del kernel ya es un runtime

    • Si no es broma, entonces hay un malentendido fundamental sobre cómo se estructura el código del kernel cuando se escribe en Rust (y en C). Al programar para el kernel, igual que con la stdlib de C, Rust funciona como no_std, y tampoco puedes usar cargo ni crates. Para usar tokio tendrías que reescribir media biblioteca y reemplazar toda la interacción con el sistema operativo, como sockets, por mecanismos propios del kernel

  • Creo que estas funciones recientes de Rust relacionadas con Linux no se limitan al kernel, sino que son de las primeras que resultan ampliamente útiles para el lenguaje Rust en general. Da la impresión de que el desarrollo de funciones centradas en el kernel había frenado un poco el avance de otras funciones del lenguaje o de bibliotecas

    • Hasta donde sé, systems programming es el área prioritaria de aplicación para Rust. La interoperabilidad es clave en sistemas operativos, embedded o sistemas complejos basados en C. Estas funciones en realidad no parecen exclusivas del kernel, sino utilidades generales muy necesarias para la programación real de sistemas

    • Hay avances para desarrollo de kernel y firmware en varios frentes, pero no siempre están en el centro de la atención de todos. Philipp en particular está impulsando cambios muy importantes en esta área

    • El papel principal de Rust es la programación de sistemas de bajo nivel. En otras áreas, los lenguajes managed compilados para userspace son una opción mucho mejor, y en sistemas construidos con estructuras como Self, Inferno o Android, me parece que no hay problema en concentrarse en estas funciones low level de estilo C

  • Estas funciones son lo bastante buenas como para ayudar no solo al kernel sino también a otras áreas (especialmente generalized projections). Me da mucho gusto que Linux esté impulsando el desarrollo del lenguaje Rust

  • Me pregunto si existen investigaciones o herramientas que usen LLM para convertir automáticamente código C a Rust. Pienso en si sería posible pedirle a un LLM que genere código Rust para chat, usb, i2c, drivers de GPU y además lo haga compilar y pasar pruebas, o incluso intentarlo con proyectos “más pequeños” como sqlite, apache o nginx

    • Como investigación no basada en LLM, existe el proyecto c2rust, con casos reales de uso. Los LLM al final se quedan en aproximaciones, no son precisos, y producen demasiados bugs sutiles. Si no se combinan con métodos formales, no son prácticos. Hay muchos problemas que tampoco saldrían a la luz con solo pruebas unitarias. Y los ejemplos que pusiste como proyectos “más pequeños” en realidad tampoco son tan pequeños. Revisa los casos reales de aplicación

    • DARPA también ha mostrado interés en esta clase de investigación y ha aportado financiamiento, pero todavía no están en una etapa con resultados concretos

 
ahwjdekf 2025-10-17

Alineación en el dogmatismo (alignment in dogmatism)