Reportar cada error de validación

Gana FxDart

Requisito

Cinco formularios de registro del lote 2026-08 se comprueban contra tres reglas (nombre presente, email con @, edad 18+). Un formulario puede romper varias reglas — reporta cada regla rota por formulario, y luego lista los formularios que pasaron. Los datos están en el código; las dos versiones deben imprimir las líneas que aparecen bajo Salida esperada.

Salida esperada
form #2: name is required; email is malformed; must be 18 or older
form #4: email is malformed
form #5: name is required; must be 18 or older
valid: ana, cy

Lado a lado

RxDart

FxDart

Por qué difieren

La validación acumulativa es el trabajo que el canal de errores de Rx es estructuralmente incapaz de hacer. Un error de stream lleva exactamente un objeto, y emitirlo termina el stream — lanza la primera regla rota y ni los demás fallos de ese formulario ni los formularios restantes se verán jamás. Cada operador de recuperación (onErrorReturn, onErrorResumeNext) está construido para esa forma de un-error-y-fin. Así que la versión RxDart funcional que se muestra aquí abandona en silencio el canal de errores: mapea cada formulario a un registro de sus fallos en el canal de datos — y llegados a ese punto el stream aporta un main async y un toList, nada más.

El lado FxDart es la misma idea sin el envoltorio: los errores son valores llanos, así que un map + partition síncronos entregan los formularios fallidos (con todos sus errores) y los válidos en una sola expresión. Y como FxDart trata los errores como valores en todas partes, este patrón escala más allá de los registros: la capa de errores tipados acumula por ti — zipOrAccumulate ejecuta cada regla y concatena los fallos en una NonEmptyList, y mapOrAccumulate valida una colección entera fail-slow. Mira el tutorial de accumulate para esa versión completa; el modelo de streams no tiene contrapartida a la que recurrir.

Benchmark

Apple M1 Max, 32 GB de RAM · Dart 3.12.2 (compilado AOT) · 2026-08-18

N = 100

Tiempo Empate

RxDart 125 µs
FxDart 27 µs

Memoria pico Gana RxDart

RxDart 15.5 MB
FxDart 16.5 MB

N = 1,000,000

Tiempo Gana FxDart

RxDart 1094.5 ms
FxDart 303.4 ms

Memoria pico Gana RxDart

RxDart 345.3 MB
FxDart 369.0 MB

Las barras son medianas de iteraciones cronometradas repetidas en procesos nuevos por lado (los N pequeños se agrupan por resolución del temporizador). Dos lados a menos del 5% entre sí — o a menos de 0.6 ms, una diferencia que nadie puede percibir — cuentan como empate; las carreras relativas ajustadas se vuelven a medir hasta 5 veces. En una app, cualquier cosa por debajo de unos pocos milisegundos es invisible para el usuario, gane la barra que gane. La memoria es el RSS pico del proceso. La VM de Dart y el dataset son idénticos en ambos lados, así que la diferencia entre las dos barras es lo que retiene el pipeline en sí.