Rust sigue sin argumentos nombrados y el precio lo pagan sus constructores
Un análisis compara cómo Dart, C# y TypeScript resuelven los parámetros con nombre y por qué el apaño habitual en Rust obliga a escribir más código del necesario
Rust no tiene argumentos nombrados ni opcionales, y quien lo escribe a diario lo nota. Un análisis reciente compara cómo lo resuelven Dart, C# y TypeScript y por qué el remedio habitual en Rust acaba siendo más verboso que el problema que intenta resolver.
Dart es el que mejor parado sale. Los parámetros nombrados van entre llaves y admiten valor por defecto, tipo nulo o la marca required para los obligatorios. Los posicionales opcionales, entre corchetes. La sintaxis recuerda a un mapa y eso la hace fácil de leer en la llamada.
C# resuelve lo mismo con menos ceremonia: cualquier parámetro se puede nombrar en la llamada, y los que van después de los obligatorios pueden llevar valor por defecto. Nada más.
TypeScript es el caso incómodo. Los posicionales opcionales funcionan bien, pero para los nombrados no hay sintaxis propia y hay que montarlos con un tipo anónimo y destructuring. El resultado obliga a declarar el nombre del campo dos veces, una en el tipo y otra en la firma. En React, donde un componente es una función que recibe un objeto, eso se escribe constantemente.
El apaño de Rust
En Rust lo más común es declarar un struct para los parámetros, implementarle Default y cerrar el inicializador con ..Default::default(). Funciona, pero arrastra más problemas que la solución de TypeScript: los tipos no son anónimos, y si los valores por defecto no coinciden con el default del propio tipo —una cadena vacía para un String, por ejemplo— hay que escribir una función entera solo para fijarlos. Peor aún, el patrón exige que todos los parámetros tengan valor por defecto. Si solo lo tienen algunos, hace falta algo todavía más largo.
El coste no es teórico. Se ve en la propia biblioteca estándar. HashMap arrastra un constructor con nombre para cada combinación: new, with_capacity, with_hasher, with_capacity_and_hasher, más las variantes _in que reciben un allocator. La lista crece a medida que se añaden ejes de configuración y cada uno es una función distinta que hay que recordar. Con argumentos nombrados y opcionales bastaría con una.
El autor enlaza además una propuesta en forma de RFC, el 3681, y el crate bon, dos de los frentes que se discuten para llevar esta capacidad al lenguaje.
Lo que está sobre la mesa no es un capricho estético. Cada parámetro opcional que no existe se convierte en un constructor más, en un struct de parámetros o en una función auxiliar, y eso lo acaba pagando quien lee el código meses después. La pregunta es si Rust mueve ficha en el lenguaje o deja que los crates carguen con el peso.