C++26 Contracts: Introducción a precondiciones y postcondiciones
La nueva funcionalidad Contracts de C++26, que añade precondiciones y postcondiciones estandarizadas a las declaraciones de funciones, está generando tanto entusiasmo como escepticismo. Los partidarios la ven como una forma de convertir el “código como documentación” en invariantes comprobables por máquinas que puedan ayudar en depuración, análisis estático, optimización e incluso herramientas de IA, sin dejar de ser opcional en tiempo de ejecución. Los críticos sostienen que la semántica es confusa —especialmente en torno a la validación de entrada y a cuándo se pueden omitir las comprobaciones—, lo que hace que Contracts parezca una forma más pesada y confusa de `assert` que quizá no cumpla las expectativas de verificación formal.
Papel de los contratos y la verificación formal
- Muchos ven los contratos de C++26 como una forma de codificar triples de Hoare (pre/post/invariantes) y generar condiciones de verificación que herramientas/solvers pueden comprobar.
- Se citan ejemplos de otros ecosistemas (Racket, SPARK/Ada, verificadores especializados de C/C++) como prueba de que un subconjunto restringido puede demostrarse estáticamente, aunque el C++ completo nunca lo sea.
- Los contratos pueden ayudar a aislar funciones “desordenadas”: demostrar todo lo que las rodea asumiendo que se cumplen pre/post, y localizar dónde falla la prueba.
Comportamiento en tiempo de ejecución vs validación de entrada
- Hay un acuerdo amplio: los contratos son para “esto nunca debe ocurrir; si ocurre, es un bug”, no para la validación normal de entrada del usuario.
- Varias personas señalan que la frontera entre “validación de entrada” y “suposiciones” es difusa y probablemente se usará mal en la práctica.
- Los contratos se comparan con
assert: papel similar, pero estandarizado, visible en la declaración, con múltiples modos de evaluación (ignore,observe, comprobación). - Las críticas se centran en el modelo de “ghost code”: debes asumir que las comprobaciones podrían omitirse, así que no se puede confiar en ellas para comportamiento de seguridad crítica.
Optimización y rendimiento
- Algunos esperan que los compiladores usen los contratos como
assumepara optimización o para eliminar comprobaciones redundantes; otros dicen que ese no es un objetivo principal del diseño. - Hay decepción porque en las implementaciones actuales, el modo
ignore(sin comprobaciones en tiempo de ejecución) no parece seguir guiando las optimizaciones. - A los desarrolladores de sistemas embebidos y alto rendimiento les gusta poder activar comprobaciones en estaciones de trabajo pero desactivarlas en las compilaciones objetivo.
Ubicación, cabeceras y módulos
- Debate sobre dónde poner los contratos: las cabeceras los exponen como documentación pero pueden forzar inclusiones pesadas; los archivos
.cppevitan eso pero pierden visibilidad. - El estándar exige que la primera declaración lleve los contratos, empujando el uso hacia las cabeceras; algunos sostienen que los módulos mitigarán los problemas de explosión del tiempo de compilación.
- Patrón sugerido: mantener simples los contratos de cabecera o delegarlos a funciones auxiliares definidas en otro lugar.
Complejidad del lenguaje y comparaciones
- Algunos ven C++ como ya demasiado grande y consideran los contratos una complejidad más para una ganancia modesta; otros dicen que esto solo formaliza un patrón usado desde hace tiempo.
- Se hacen comparaciones con Eiffel, D, Clojure, Racket, Rust y Go: muchos otros lenguajes tienen contratos o facilidades de pre/post, con experiencias mixtas sobre su utilidad en el mundo real.
Utilidad, seguridad y herramientas
- Los partidarios destacan beneficios para IDEs, analizadores estáticos, agentes de IA y como “documentación ejecutable” precisa.
- Los escépticos argumentan que los contratos son “solo asserts más sofisticados”, no pueden garantizar su ejecución y pueden incluso ser menos seguros que
assertpuro en algunos patrones. - En general: optimismo cauteloso sobre el potencial de herramientas y verificación, junto con un escepticismo considerable sobre el beneficio práctico cotidiano y los compromisos de diseño.