El problema fundamental que aborda esta propuesta es la gestión y composición de los "efectos" en lenguajes de programación de sistemas como Rust. Tradicionalmente, los efectos (como la asincronía, el acceso a la memoria, la fallibilidad o el no determinismo) se manejan de forma ad-hoc, lo que lleva a inconsistencias sintácticas, bifurcaciones de la biblioteca estándar y una complejidad creciente a medida que se añaden nuevos comportamientos. La tesis central es que un sistema formal y unificado para describir y razonar sobre los efectos, similar a cómo los sistemas de tipos describen los datos, puede simplificar significativamente la experiencia del desarrollador y aumentar la expresividad del lenguaje.

La motivación actual para esta propuesta en Rust surge de la necesidad de escalar los dos efectos estables existentes (asincronía y fallibilidad implícita) a un conjunto más amplio de comportamientos, manteniendo la compatibilidad con versiones anteriores y la familiaridad del lenguaje. Esto se conecta con la búsqueda histórica en la informática de abstracciones que permitan razonar sobre propiedades no funcionales del código de manera composable y verificable, un desafío que ha llevado al desarrollo de conceptos como mónadas, efectos algebraicos y sistemas de tipos con efectos.

Arquitectura del Sistema

La propuesta introduce un sistema de efectos basado en tres palabras clave principales: eff, with y .do. eff se utiliza para declarar "genéricos de efecto" (variables de tipo de efecto) y "ítems de efecto" (alias de efecto o efectos asociados). La palabra clave with se emplea para definir el contexto de un efecto, aplicable a bloques, closures, funciones, métodos e implementaciones de traits. Esto reemplaza la sintaxis actual de prefijos (ej. async fn) por una cláusula explícita, permitiendo la composición de múltiples efectos (ej. fn foo() with async + emplace { .. }).

Para efectos con parámetros genéricos (como iteración o fallibilidad que devuelven tipos específicos), la notación se extiende para incluir tipos de entrada y salida (ej. gen(i32) -> u32 o throw(None)). Esto permite modelar coroutines tipadas. La propuesta también aborda el "polimorfismo de efectos", donde las funciones pueden ser genéricas sobre un conjunto de efectos (fn foo<eff Ef>() -> i32 with Ef { .. }), permitiendo la creación de código agnóstico a efectos. Se introduce un "álgebra de efectos" que permite operaciones como la unión (Ef3: Ef1 + Ef2), la exclusión (Ef: !Block) y la exclusión mutua, utilizando la cláusula where para establecer restricciones. Finalmente, el operador .do se propone para la propagación genérica de efectos dentro de los cuerpos de las funciones, actuando como un unificador para operaciones como .await, ? o yield en contextos polimórficos de efectos. Se discute la posibilidad de un cambio de paradigma donde Rust asuma la "totalidad" (ausencia de efectos) por defecto, con mecanismos de opt-in a nivel de módulo o crate para efectos como panic, diverge, heap o syscalls mediante mod self with Std; o crate self with Alloc;.

fn foo() -> i32 with async + emplace { .. }
Muestra cómo una función puede declarar múltiples efectos utilizando la cláusula `with` y el operador `+`.
let foo = || with async { .. };
Ilustra la aplicación de un efecto a una closure, manteniendo la consistencia con funciones y bloques.
fn foo<F, eff Ef>(f: F) -> i32
where
    F: FnOnce() -> i32 with Ef,
with Ef {
    f().do; // inserts `.await`, `?`, `for..in..yield` as needed
}
Define una función que es polimórfica sobre un efecto `Ef`, propagando este efecto a través de su cuerpo con `.do`.
eff Alias = async + emplace;
Define un alias para un conjunto de efectos, permitiendo la reutilización y abstracción de firmas de efectos complejas.
fn get_foo(x: Bar) -> Foo
with async
+ gen(i32) -> u32
+ try(Option<!>)
{ .. }
Ejemplo de cómo los efectos pueden llevar tipos genéricos para especificar entradas y salidas, como en iteración o fallibilidad.
mod self with Std;
pub fn foo() {} // `with Std` is implied
Muestra cómo se pueden aplicar efectos por defecto a todos los ítems dentro de un módulo o crate, simplificando la anotación en proyectos grandes.

Fundamentos Teóricos

La propuesta se basa en el campo de los sistemas de tipos con efectos, un área de investigación activa en la teoría de lenguajes de programación. El concepto de "efectos" en sí mismo tiene raíces profundas en la semántica operacional y denotacional, buscando formalizar y controlar los aspectos no puros de los programas. La idea de "efectos algebraicos" y sus "manejadores" (effect handlers) es particularmente relevante, como se detalla en trabajos como "Structured asynchrony with algebraic effects" de D. Leijen (2017), que modela la asincronía, la iteración y la fallibilidad como efectos manejables.

La discusión sobre el álgebra de efectos, incluyendo la unión, exclusión y exclusión mutua, se inspira directamente en investigaciones como "With or Without You: Programming with Effect Exclusion" de Lutze, Madsen, Schuster y Brachthäuser (2023), que explora cómo expresar estas condiciones en sistemas de tipos con efectos. Aunque el artículo menciona las mónadas como una alternativa para modelar efectos arbitrarios (especialmente la mónada libre), la propuesta se inclina por un sistema de efectos más integrado y sintácticamente ligero, buscando una solución más idiomática para Rust que aborde directamente los problemas de orden y composición sin la complejidad de las mónadas libres para el usuario final. La noción de "totalidad" como la ausencia de todos los efectos se alinea con lenguajes funcionales puros y lenguajes con sistemas de efectos explícitos como Koka.