Biblioteca estándar del día de la muerte

El otro día en Praga, el comité de estandarización de C ++ realizó una serie de encuestas sobre el tema de cambiar el ABI, y finalmente se decidió no cambiar nada en él. No hubo aplausos en el pasillo.
Creo que no nos dimos cuenta plenamente de las consecuencias que conllevaría esta decisión, y no creo que, en principio, pueda afectar positivamente el desarrollo del lenguaje.



¿Qué es el ABI?


ABI: un conjunto de convenciones que definen cómo se representa su programa en forma binaria, cómo se declaran los nombres en él, se define el marcado de clase y se definen las convenciones de llamada a funciones. De hecho, este es un tipo de protocolo binario, pero no está versionado.
Para no confundirlo con la terminología, veamos ejemplos de lo que implica el cambio de ABI y su desglose dentro del programa:

no puede usar el símbolo exportado en la nueva versión de su biblioteca compilada si realizó alguna de las siguientes acciones:

  • Se agregó un nuevo campo a una clase existente
  • Cambió los parámetros de plantilla de la clase / función, convirtió la función de plantilla en una plantilla que no es plantilla, o viceversa, agregó una plantilla variada
  • Aplicar el especificador en línea a algo
  • Parámetros predeterminados agregados en la declaración de función
  • Nuevo método virtual anunciado

Y mucho, mucho más, pero los ejemplos anteriores son los principales mencionados por el comité, y los mismos, gracias a los cuales la mayoría de las propuestas de la norma se destruyen en el acto. Omití las opciones para violar el ABI, durante el cual el código fuente del programa también se rompe (por ejemplo, eliminar o cambiar funciones). Sin embargo, esto no siempre es cierto. Por ejemplo, eliminar una función no siempre implica romper el código fuente. std::stringTiene un operador de conversión std::string_view, del que me gustaría deshacerme, y aunque eliminarlo romperá la ABI, no generará problemas significativos en el código fuente.

¿Por qué deberíamos romper ABI


En primer lugar, hay varios cambios útiles en la implementación de la biblioteca estándar que puede implementar si rompe la ABI actual:

  • Hacer contenedores asociativos (mucho) más rápido
  • Acelere su trabajo std::regex(en este momento, es más rápido ejecutar PHP y buscar en él con una expresión regular que usar el estándar std::regex)
  • Algunos cambios en std::string, std::vectorasí como en el diseño de otros contenedores
  • Unidad de la interfaz de clase: por el momento, algunas de sus implementaciones intencionalmente no corresponden a una sola interfaz por el bien de la estabilidad ABI

Más importante aún, hay cambios en el diseño de la biblioteca que no se pueden realizar sin encontrar el problema de seguridad ABI. Aquí hay una lista incompleta de todo lo que actualmente no es factible por la razón mencionada anteriormente:

  • std::scoped_lock fue agregado para no romper el cambio abi lock_guard
  • int128_t , intmax_t. , , , intmax_t deprecated
  • std::unique_ptr , zero-overhead
  • error_code - , ABI
  • status_code ABI
  • recursive_directory_iterator , ABI
  • <cstring> constexpr ( strlen) , ABI
  • UTF-8 std::regex — ABI
  • agregar soporte reallocy devolver el tamaño de la memoria asignada es un desglose de ABI para los asignadores polimórficos
  • Creación de destructores virtuales implícitos para tipos polimórficos
  • el tipo de retorno y push_backse puede cambiar si el ABI actual está roto
  • En general, ¿realmente necesitamos y push_back, y emplace_back?
  • std::shared_ptr también causa desglose ABI
  • [[no_unique_address]] el compilador podría generar resultados si no nos importara guardar el ABI actual

Y la lista no termina ahí. Creo que WG21 debería tratar de mantener actualizada la lista de tales cosas. Pero tomaré nota de todos los que dicen "romperá el ABI", estando conmigo en la misma habitación.

¿Qué más queremos cambiar?


No lo sé. Y no sé lo que no sé. Pero si me pidieran adivinar, diría lo siguiente:

  • C++23 ABI, - , ABI.
  • , , , , ABI
  • ABI,
  • , ABI
  • Tombstone ABI

ABI


Durante la última discusión de ABI, se realizaron una serie de encuestas en Praga, que, sin embargo, no nos dicen nada. Dependiendo de si usted es pesimista u optimista, los resultados actuales pueden ser interpretados por usted de manera diferente.

Hechos clave:

  • WG21 no quiere romper ABI en 23
  • WG21 considera necesario romper el ABI en futuras versiones de C ++ (C ++ 26 o posterior)
  • WG21 tomará tiempo para considerar propuestas que violen ABI
  • WG21 no promete estabilidad eterna
  • WG21 considera importante mantener la prioridad en el rendimiento, incluso en detrimento de la estabilidad del lenguaje.

Estas declaraciones tienen muchos puntos importantes, pero no hay consenso. El comité, por extraño que parezca, se dividió por la mitad.

Adivinación


En qué versión de C ++ esperar los cambios


El inconveniente obvio de todas estas encuestas es que no hemos decidido cuándo exactamente queremos romper el ABI.

en c ++ 23? No, definitivamente no ya.

en C ++ 26? Algunas personas tienen la intención de votar, pero es probable que otra parte vote por C ++ 41 o por el momento en que se retiren y no tengan que apoyar su proyecto actual. Una de las preguntas acaba de mencionar C ++: algunas ; muy comodamente!

No hay razón para creer que si el ABI no se puede violar ahora, se puede violar más tarde. Las personas que necesitan estabilidad están varios años atrás del estándar. Entonces, si no lo rompemos ahora, las personas continuarán confiando en el ABI nunca prometido, tal vez otros diez o incluso veinte años. El simple hecho de que realizamos esta encuesta finalmente votó por no violar el ABI, muestra que todo el ecosistema se está volviendo pedregoso y estancado gradualmente: cada día el problema solo empeora y es potencialmente más costoso.

No creo que algo cambie en la encuesta realizada en tres años. Es como el calentamiento global: todos están de acuerdo en que algún día tenemos que abordar este problema. ¿Y luego prohibamos el diésel en 2070?

Es probable que nunca suceda todo lo que no se planea hacer en los próximos cinco años.

Acerca de las ofertas que violan ABI


WG21 votó para dedicar más tiempo a las propuestas que violan el ABI actual. Esto significa algunas cosas:

  • Perderemos más tiempo en una de las salas más ruidosas del comité para discutir este tema y dejaremos menos en aquellas propuestas que tengan más posibilidades de adopción, y al final las rechazaremos de todos modos.
  • Buscaremos alternativas que no rompan ABI (esto se discutirá a continuación)
  • Se pueden introducir cambios parciales en ABI (ver también a continuación)

El rendimiento es más importante que la estabilidad ABI


Es como preguntar si un niño de cinco años quiere un dulce. Por supuesto, votaremos sobre la importancia del rendimiento. Sin embargo, me preocupa que algunas personas todavía voten en contra.

Me parece que el comité simultáneamente quiere sentarse en dos sillas a la vez. Y esto es imposible:
Bryce Adelstein Lelbach @blebach
- Rendimiento
- Estabilidad ABI
- Capacidad de cambiar algo

Elija dos opciones de las propuestas.

la estabilidad del lenguaje y el ABI, por supuesto, chocan entre sí, lo que nos obliga a hacer una pregunta tan fundamental: ¿qué es C ++ y cuál es su biblioteca estándar?

Por lo general, en este caso, se recuerdan los términos "rendimiento", " abstracción de costo cero ", " no pague por lo que no usa ". Y la estabilidad de ABI se destaca en todo esto.

Consecuencias de largo alcance


imagen

Estoy profundamente convencido de que la decisión de no romper el ABI en el año 23 es el mayor error que ha cometido el comité. Y sé que algunas personas creen lo contrario. Pero esto es lo que probablemente sucederá pronto:

Pesadilla de aprendizaje


Seamos honestos. Es probable que todos los programas que dependen de ABI violen los principios de ODR en algún lugar o utilicen indicadores incompatibles, que, afortunadamente, todavía funcionan.

Los nuevos programas deben compilarse a partir del código fuente, necesitamos herramientas integradas en el ensamblaje a partir de las fuentes, y no una colección de bibliotecas que obtuvimos de alguna parte e insertadas de alguna manera en el proyecto.

Sí, construir desde la fuente es algo que no es tan fácil de lograr. Pero debemos alentar este enfoque del producto, actualizar periódicamente los compiladores para que las personas se beneficien de las funciones recién introducidas un mes después del lanzamiento, y no diez años después. Es necesario alentar soluciones correctas, confiables, escalables y reproducibles, bibliotecas de código abierto y un sistema de dependencia.

Al negarse a violar ABI, el comité declara abiertamente que apoyará programas mal escritos a lo largo de su existencia. Incluso si no se vincula a las bibliotecas obtenidas a través de apt-install (que en realidad están destinadas al sistema), habrá otras personas, porque el comité les dio su bendición.

Este es un gran paso atrás. ¿Cómo podemos enseñar a otros buenas prácticas lingüísticas si no tenemos incentivos para hacerlo?

Pérdida de interés en la biblioteca estándar.


La pérdida estimada en el rendimiento de la biblioteca debido a nuestra falta de voluntad para violar ABI se estima en 5-10%. Este número solo crecerá con el tiempo. Veamos ejemplos:

  • Si es una gran empresa, puede comprarse un nuevo centro de datos o pagar a un equipo de programadores que apoyarían su propia biblioteca
  • , 5% ,
  • , 5-10% , VR-
  • , —

Creo que aquí, de todos modos, surge la pregunta entre: "¡Definitivamente debería usar C ++ y su biblioteca estándar!" y "¿Quizás no debería usar la biblioteca estándar? ¿O tal vez no debería usar C ++ en principio? ¿Quizás .NET, julia o Rust serían una mejor solución? Por supuesto, hay muchos factores que influyen en la respuesta, pero vemos lo que está sucediendo recientemente.

Muchos desarrolladores de juegos son extremadamente escépticos de la biblioteca estándar. Prefieren desarrollar su propia alternativa, como EASTL , que aprovechar STL. Facebook tiene locura , Google tiene rapeles, etc.

Es como una bola de nieve. Si las personas no usan la biblioteca estándar, no tienen interés en mejorarla. El rendimiento es el factor clave que mantiene a flote la biblioteca. Sin una garantía de rendimiento, se pondrá mucho menos esfuerzo en su desarrollo.
>> Jonathan Müller @foonathan
¿Cuál es el punto de usar contenedores de la biblioteca estándar si no proporcionan un mejor rendimiento?

Titus Winters @TitusWinters ¿
Quizás porque son comunes y de fácil acceso? (Estos dos hechos no significan lo mismo).
Votar por la preservación de ABI es como decir que la biblioteca estándar debería esforzarse por ser McDonald's: también está en todas partes, es estable y técnicamente resuelve las tareas.

¿Cómo puede un comité considerar propuestas que rompan una ABI?


Se ofrecen varias opciones como alivio del dolor causado por la incapacidad de aceptar ofertas si violan el ABI:

Agregar nuevos nombres


imagen

Esta es la primera y obvia solución. Si no podemos cambiar std::unordered_map, ¿podemos simplemente agregar std::fast_map? Hay varias razones por las cuales esto es malo. Agregar tipos a la biblioteca estándar es costoso, tanto en términos de costos de soporte como en términos de educación. Después de la introducción de la nueva clase, inevitablemente aparecerán miles de artículos, explicando qué contenedor debe usarse. Por ejemplo, ¿debería usar std::scoped_locko std::lock_guard? ¡No tengo idea! Necesito googlear todo el tiempo. También existe el problema de que los buenos nombres terminan tarde o temprano. También recibimos algunos gastos generales durante la ejecución del programa, ya que todos los contenedores deben convertirse constantemente entre sí, se hace difícil controlar una gran cantidad de sobrecargas de conversión en la clase, etc.

Es irónico, pero las personas que respaldan la solución anterior también pueden argumentar que C ++ es un lenguaje demasiado complejo. Agregar duplicados a la biblioteca definitivamente no lo hará más fácil.

¡Pero podríamos aceptar esta oferta como estándar!


Algunos desarrolladores de bibliotecas afirman que sus ofertas fueron rechazadas debido a una violación de ABI, aunque en realidad no violaron nada, o podrían modificarse para evitar la falla de ABI.

Como persona cínica, es un poco difícil de creer para mí. El hecho es que antes no existían tales propuestas, y los escenarios en los que se pueden aplicar son muy limitados. ABI Review Group (ARG) podría ayudar en este asunto, pero es probable que recomienden otro nombre para la clase / función nuevamente.

Violación parcial de Abi


La idea principal no es romper todo el ABI, sino solo cambiarlo para una clase o función específica. El problema con este enfoque es que, en lugar de un error en la etapa de vinculación, ya veremos el problema durante el lanzamiento del programa, y ​​será desagradable sorprendernos. El comité ya había intentado este enfoque en C ++ 11 cuando cambió el marcado std::string. Nada bueno salió de eso. Todo fue tan malo que este hecho todavía se usa como argumento a favor de mantener el ABI actual.

Otro nivel de indexación


La solución a algunos de los problemas con ABI sería la capacidad de acceder a los datos de la clase a través de un puntero, luego el marcado de la clase sería solo ese puntero. La idea está muy cerca del lenguaje PIMPL , que se usa activamente en Qt debido a su ABI. Sí, eso resolvería el problema con los miembros de la clase, pero ¿qué hacer con los métodos virtuales?

Considerando el problema desde un punto de vista más crítico, estamos hablando de agregar otro nivel de indirección (un índice por puntero) y una asignación adicional de memoria en el montón para todo lo que está incluido en el marco de ABI. En STL, de hecho, todo está encerrado dentro de este marco porque es una colección de clases generalizadas.

Como resultado, el precio de este enfoque será enorme.

Como solución a este problema, ya hay varias propuestas en el estándar. Algunos de ellos quieren hacer de PIMPL una de las características del lenguaje, para que pueda elegir entre la estabilidad ABI y el alto rendimiento.

Irónicamente, sin embargo, pero para convertir los tipos de biblioteca en tipos PIPML, necesitamos ... romper el ABI.

Vuelva a armar todo el código cada tres años.


Solo mis pensamientos en voz alta.

Todas las ofertas actuales en el estándar deben ser destruidas


Paradójicamente, C ++ nunca ha sido tan animado como ahora. En Praga, 250 personas trabajaron en muchas cosas para él, incluyendo:

  • Numéricos
  • Álgebra lineal
  • Audio
  • Unicode
  • E / S asincrónica
  • Gráficos 2D y 3D
  • Muchas otras características

Todas estas propuestas están unidas por un hecho común: son mucho más opcionales en comparación con lo que tenemos en el estándar en este momento. La gente simplemente está tratando de estandarizar las cosas de su campo de investigación y trabajo, o lo que está en constante evolución y cambio.
En particular, los algoritmos Unicode son extremadamente inestables y cambian rápidamente con el tiempo.

Y luego, tal horror como las redes se ciernen en el horizonte . Es muy, muy irresponsable tratar de estandarizar cualquier cosa que pueda conducir a problemas de seguridad, y al mismo tiempo no poder cambiarlo más tarde (recuerde ABI).

Dado que C ++ decidió hacerlo estable, todas estas sugerencias deben ser destruidas y quemadas. No quisiera ser destruido, pero esto debe hacerse.

Pero todavía no lo harán.

En el mejor de los casos, no cometeremos errores y estandarizaremos el estado actual de las cosas en una de las nuevas versiones de C ++, y luego dejaremos que todo se descomponga lentamente, ya que no será posible solucionarlo (en el caso de Networking TS, parece que no podemos cambiar nada, por lo tanto, tendremos que estandarizar lo que existió hace diez años, luego, por supuesto, la biblioteca aún puede mejorarse significativamente, pero dejemos esta historia para otro momento).

Pero, por supuesto, cometeremos muchos, muchos errores.

>> Ólafur Waage @olafurw
( , )

, !

. , ( : , , )?

Hyrum Wright @hyrumwright
, , . — , .

Algunos errores se cometen intencionalmente, ya que son compensaciones, mientras que otros pasan desapercibidos durante muchos años.

El tiempo pasa, pero la biblioteca estándar se detiene. Las compensaciones realizadas anteriormente comienzan a interferir gradualmente con nosotros y luego se convierten en verdaderos "cuellos de botella" en el código existente.

Algunas cosas son realmente imposibles de cambiar, ya que están integradas en la API. Todos tenemos una idea de lo difícil que es cambiar una API existente. Pero parte del código aún puede repararse y mejorarse si pudiéramos romper el ABI.

C ++ seguirá a flote en los próximos 40 años. Si no podemos darnos cuenta de la necesidad de cambiarlo de forma impredecible en cualquier momento, entonces el único movimiento correcto será, en principio, no jugar este juego.

Todos saben que un contenedor asociativo estándar ha sido relevante para su uso durante menos de diez años. Pero, ¿por qué pensamos que las propuestas más grandes en el estándar serán más exitosas?

Su oferta al estándar será destruida, la mía será destruida de la misma manera.

¿Puede un comité, en principio, romper una ABI?


Muchos están seguros de que el comité no puede, en principio, tomar tal decisión, porque los desarrolladores de la biblioteca simplemente lo ignorarán. Todo esto se asemeja dolorosamente a la lucha de brazos, en la que el comité decidió no jugar.

Pero el hecho es que los desarrolladores de cualquier producto tienen sus propios usuarios. Los usuarios son aquellos que, en primer lugar, necesitan comprender qué compensaciones se les imponen.

Muchas personas confían en ABI por accidente, sin tomar una decisión informada. Muchas personas también confían en la estabilidad porque, por supuesto, todos quieren confiar en ella. Pero como cualquier otra cosa, la estabilidad tiene un precio, y ahora todo el ecosistema C ++ lo paga.

All Articles