Biblioteca Padrão da Morte

Outro dia em Praga, o comitê de padronização do C ++ conduziu uma série de pesquisas sobre a questão da mudança da ABI e, finalmente, foi decidido não mudar nada nela. Não houve aplausos no corredor.
Acho que não percebemos completamente as consequências que essa decisão acarretaria e não acredito que, em princípio, possa afetar positivamente o desenvolvimento da linguagem.



O que é ABI?


ABI - um conjunto de convenções que definem como seu programa é representado na forma binária, como os nomes são declarados nele, a marcação de classe é definida e as convenções de chamada de função são definidas. De fato, este é um tipo de protocolo binário, mas não é versionado.
Para não confundi-lo na terminologia, vejamos exemplos do que a alteração ABI implica e sua divisão no programa:

Você não pode usar o símbolo exportado na nova versão da sua biblioteca compilada se tiver feito o seguinte:

  • Adicionado um novo campo a uma classe existente
  • Foram alterados os parâmetros do modelo da classe / função, transformado a função do modelo em um não modelo ou vice-versa, adicionado modelo variadico
  • Aplique o especificador inline a algo
  • Adicionados parâmetros padrão na declaração da função
  • Novo método virtual anunciado

E muito, muito mais, mas os exemplos acima são os principais mencionados pelo comitê e os mesmos, graças aos quais a maioria das propostas na norma é destruída no local. Omiti as opções de violação da ABI, durante as quais o código-fonte do programa é interrompido (por exemplo, excluindo ou alterando funções). No entanto, isso nem sempre é verdade. Por exemplo, excluir uma função nem sempre implica quebrar o código fonte. std::stringEle possui um operador de conversão std::string_view, do qual eu me livraria com prazer e, embora a exclusão do mesmo interrompa a ABI, não causará problemas significativos no código-fonte.

Por que devemos quebrar a ABI


Primeiro de tudo, há várias alterações úteis na implementação da biblioteca padrão que você pode implementar se quebrar a ABI atual:

  • Torne os recipientes associativos (muito) mais rápidos
  • Acelere seu trabalho std::regex(no momento, é mais rápido executar o PHP e pesquisá-lo com uma expressão regular do que a padrão std::regex)
  • Algumas mudanças std::string, std::vectorbem como no layout de outros contêineres
  • Unidade da interface da classe: no momento, algumas de suas implementações intencionalmente não correspondem a uma única interface em prol da estabilidade da ABI

Mais importante, há mudanças no design da biblioteca que não podem ser feitas sem encontrar o problema de segurança da ABI. Aqui está uma lista incompleta de tudo o que atualmente não é viável pelo motivo mencionado acima:

  • std::scoped_lock foi adicionado para não quebrar a alteração 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
  • adicionar suporte realloce retornar o tamanho da memória alocada é uma quebra da ABI para alocadores polimórficos
  • Criando destruidores virtuais implícitos para tipos polimórficos
  • o tipo de retorno y push_backpode ser alterado se a ABI atual estiver quebrada
  • Em geral, realmente precisamos e push_back, e emplace_back?
  • std::shared_ptr também causa quebra de ABI
  • [[no_unique_address]] poderia ser produzido pelo compilador se não nos importássemos em salvar a ABI atual

E a lista não termina aí. Eu acho que o WG21 deveria tentar manter atualizada a lista de tais coisas. Mas vou tomar nota de todos que dizem "isso quebrará a ABI", estando comigo na mesma sala.

O que mais queremos mudar?


Eu não sei. E não sei o que não sei. Mas se me pedissem para adivinhar, eu diria o seguinte:

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

ABI


Durante a última discussão da ABI, foram realizadas várias pesquisas em Praga, que, no entanto, não nos dizem nada. Dependendo de você ser pessimista ou otimista, os resultados atuais podem ser interpretados por você de maneira diferente.

Principais fatos:

  • O WG21 não quer quebrar a ABI em 23
  • O WG21 considera necessário interromper a ABI em versões futuras do C ++ (C ++ 26 ou posterior)
  • O GT21 levará tempo para considerar propostas que violam a ABI
  • O GT21 não promete estabilidade eterna
  • O GT21 considera importante manter a prioridade no desempenho, mesmo em detrimento da estabilidade da linguagem

Essas declarações têm muitos pontos importantes, mas não há consenso. O comitê, curiosamente, se dividiu ao meio.

Cartomancia


Em qual versão do C ++ aguardar alterações


A desvantagem óbvia de todas essas pesquisas é que ainda não decidimos quando exatamente queremos quebrar a ABI.

em c ++ 23? Não, definitivamente ainda não.

em C ++ 26? Algumas pessoas pretendem votar, mas outra parte provavelmente votará no C ++ 41 ou no momento em que se aposentarem e não precisarão apoiar o projeto atual. Uma das perguntas mencionadas apenas em C ++ - algumas ; muito confortavelmente!

Não há razão para acreditar que se a ABI não puder ser violada agora, poderá ser violada posteriormente. Pessoas que precisam de estabilidade estão vários anos atrás do padrão. Portanto, se não quebrarmos agora, as pessoas continuarão a confiar na ABI nunca prometida, talvez outros dez ou até vinte anos. O simples fato de termos conduzido essa pesquisa acabou votando para não violar a ABI mostra que todo o ecossistema está gradualmente estagnado e estagnado - todos os dias o problema só piora e é potencialmente mais caro.

Não acho que algo vai mudar na pesquisa realizada em três anos. É como o aquecimento global: todos concordam que um dia precisamos resolver esse problema. E então vamos proibir o diesel em 2070?

Tudo o que não está planejado para ser feito nos próximos cinco anos provavelmente nunca acontecerá.

Sobre ofertas que violam a ABI


O WG21 votou para dedicar mais tempo às propostas que violam a ABI atual. Isso significa algumas coisas:

  • Perderemos mais tempo em uma das salas mais barulhentas do comitê para discutir esse assunto e deixar menos propostas com mais chances de adoção, e no final as rejeitaremos da mesma forma.
  • Procuraremos alternativas que não quebrem a ABI (isso será discutido abaixo)
  • Alterações parciais na ABI podem ser introduzidas (veja também abaixo)

O desempenho é mais importante que a estabilidade da ABI


É como perguntar se uma criança de cinco anos quer um doce. Claro que vamos votar na importância do desempenho. Receio, no entanto, que algumas pessoas ainda tenham votado contra.

Parece-me que a comissão ao mesmo tempo quer se sentar em duas cadeiras ao mesmo tempo. E isso é impossível:
Bryce Adelstein Lelbach @blebach
- Desempenho
- Estabilidade ABI
- Capacidade de mudar algo

Escolha duas opções dentre as propostas.

a estabilidade da linguagem e da ABI, é claro, colidem, forçando-nos a fazer uma pergunta tão fundamental - O que é C ++ e qual é sua biblioteca padrão?

Normalmente, neste caso, os termos “desempenho”, “ abstração de custo zero ”, “ não pagam pelo que você não usa ” são lembrados . E a estabilidade da ABI está presente em tudo isso.

Consequências de longo alcance


imagem

Estou profundamente convencido de que a decisão de não quebrar a ITB no 23º ano é o maior erro que o comitê já cometeu. E eu sei que algumas pessoas acreditam no contrário. Mas aqui está o que provavelmente acontecerá em breve:

Pesadelo de aprender


Sejamos honestos. Todos os programas que dependem da ABI provavelmente violam os princípios da ODR em algum lugar ou usam sinalizadores incompatíveis, que, felizmente, ainda funcionam.

Novos programas devem ser compilados a partir do código-fonte, precisamos de ferramentas construídas no assembly a partir das fontes, e não uma coleção de bibliotecas que obtivemos de algum lugar e de alguma forma inseridas no projeto.

Sim, construir a partir da fonte é algo que não é tão fácil de conseguir. Mas precisamos incentivar essa abordagem do produto, atualizar regularmente os compiladores para que as pessoas se beneficiem dos novos recursos introduzidos um mês após o lançamento e não dez anos depois. Soluções corretas, confiáveis, escaláveis ​​e reproduzíveis, bibliotecas de código aberto e um sistema de dependência precisam ser incentivados.

Recusando-se a violar a ABI, o comitê declara abertamente que apoiará programas mal escritos por toda a sua existência. Mesmo que você não faça o link para as bibliotecas obtidas através do apt-install (que são realmente destinadas ao sistema), haverá outras pessoas, porque o comitê lhes deu suas bênçãos.

Este é um grande passo para trás. Como podemos ensinar aos outros boas práticas de linguagem se não temos incentivo para isso?

Perda de interesse na biblioteca padrão


A perda estimada no desempenho da biblioteca devido à nossa falta de vontade de violar o ITB é estimada em 5-10%. Esse número só aumentará com o tempo. Vejamos exemplos:

  • Se você é uma empresa grande, pode comprar um novo data center ou pagar uma equipe de programadores que suportariam sua própria biblioteca.
  • , 5% ,
  • , 5-10% , VR-
  • , —

Penso que aqui, quer ou não, surge a pergunta entre: "Definitivamente, devo usar C ++ e sua biblioteca padrão!" e “Talvez eu não deva usar a biblioteca padrão? Ou talvez eu não deva usar C ++ em princípio? Talvez .NET, julia ou Rust sejam uma solução melhor? ” Obviamente, existem muitos fatores que influenciam a resposta, mas vemos o que está acontecendo recentemente.

Muitos desenvolvedores de jogos são extremamente céticos em relação à biblioteca padrão. Eles preferem desenvolver sua própria alternativa, como o EASTL , do que tirar proveito do STL. O Facebook tem tolice , o Google tem rapel e assim por diante.

É como uma bola de neve. Se as pessoas não usam a biblioteca padrão, elas não têm interesse em melhorá-la. O desempenho é o fator principal que mantém a biblioteca em funcionamento. Sem uma garantia de desempenho, muito menos esforço será colocado em seu desenvolvimento.
>> Jonathan Müller @foonathan
Qual é o sentido de usar contêineres da biblioteca padrão se eles não oferecem melhor desempenho?

Titus Winters @TitusWinters
Talvez porque sejam comuns e facilmente acessíveis? (esses dois fatos não significam a mesma coisa).
Votar para preservar a ABI é como dizer que a biblioteca padrão deve se esforçar para ser o McDonald's - ele também está em todo lugar, é estável e resolve tecnicamente as tarefas.

Como um comitê pode considerar propostas que violem uma ABI?


Várias opções são oferecidas como alívio da dor causada pela incapacidade de aceitar ofertas se violarem a ABI:

Adicionando novos nomes


imagem

Esta é a primeira e óbvia solução. Se não podemos mudar std::unordered_map, podemos apenas adicionar std::fast_map? Existem várias razões pelas quais isso é ruim. Adicionar tipos à biblioteca padrão é caro, tanto em termos de custos de suporte quanto em termos de educação. Após a introdução da nova classe, milhares de artigos aparecerão inevitavelmente, explicando qual contêiner deve ser usado. Por exemplo, devo usar std::scoped_lockou std::lock_guard? Eu não faço ideia! Eu preciso pesquisar no google toda vez. Há também o problema de que bons nomes terminam mais cedo ou mais tarde. Também recebemos alguma sobrecarga durante a execução do programa, já que todos os contêineres devem ser constantemente convertidos entre si, fica difícil controlar um grande número de sobrecargas de conversão na classe, etc.

É irônico, mas as pessoas que suportam a solução acima também podem argumentar que o C ++ é uma linguagem muito complexa. Adicionar duplicados à biblioteca definitivamente não facilitará.

Mas poderíamos aceitar esta oferta como padrão!


Alguns desenvolvedores de bibliotecas afirmam que suas ofertas foram rejeitadas devido a uma violação da ABI, embora não tenham realmente violado nada ou que possam ser alteradas para contornar a falha da ABI.

Como uma pessoa cínica, é um pouco difícil para eu acreditar. O fato é que antes essas propostas não existiam e os cenários nos quais elas podem ser aplicadas são muito limitados. O Grupo de Revisão da ABI (ARG) pode ajudar nesse assunto, mas é provável que recomende outro nome para a classe / função novamente.

Violação parcial da Abi


A idéia principal não é quebrar a ABI inteira, mas apenas alterá-la para uma classe ou função específica. O problema dessa abordagem é que, em vez de um erro no estágio de vinculação, já veremos o problema durante o lançamento do programa e será desagradável nos surpreender. O comitê já havia tentado essa abordagem no C ++ 11 quando mudou a marcação std::string. Nada de bom veio disso. Tudo estava tão ruim que esse fato ainda é usado como argumento a favor da manutenção da ABI atual.

Outro nível de indexação


Uma solução para alguns dos problemas com a ABI seria a capacidade de acessar os dados da classe por meio de um ponteiro; a marcação da classe seria apenas esse ponteiro. A idéia está muito próxima do idioma PIMPL , que é usado ativamente no Qt por causa de sua ABI. Sim, isso resolveria o problema com os alunos, mas o que fazer com os métodos virtuais?

Considerando o problema de um ponto de vista mais crítico, estamos falando em adicionar mais um nível de indireção (índice de ponteiro) e alocação adicional de memória no heap para tudo o que está incluído na estrutura da ABI. Na STL, de fato, tudo está incluído nessa estrutura porque é uma coleção de classes generalizadas.

Como resultado, o preço dessa abordagem será enorme.

Como solução para esse problema, já existem várias propostas no padrão. Alguns deles querem tornar o PIMPL um dos recursos do idioma, para que você possa escolher entre a estabilidade da ABI e o alto desempenho.

Ironicamente, no entanto, mas para transformar tipos de bibliotecas em tipos PIPML, precisamos ... quebrar a ABI.

Remonte todo o código a cada três anos


Apenas meus pensamentos em voz alta.

Todas as ofertas atuais no padrão devem ser destruídas


Paradoxalmente, o C ++ nunca foi tão animado como é agora. Em Praga, 250 pessoas trabalharam em muitas coisas para ele, incluindo:

  • Numéricos
  • Álgebra Linear
  • Áudio
  • Unicode
  • E / S assíncrona
  • Gráficos 2D e 3D
  • Muitos outros recursos

Todas essas propostas são unidas por um fato comum - são muito mais opcionais em comparação com o que temos no padrão no momento. As pessoas estão simplesmente tentando padronizar as coisas do seu campo de pesquisa e trabalho, ou daquilo que está constantemente evoluindo e mudando.
Em particular, os algoritmos Unicode são extremamente instáveis ​​e mudam rapidamente ao longo do tempo.

E então, horror como a rede paira sobre o horizonte . É muito, muito irresponsável tentar padronizar qualquer coisa que possa levar a problemas de segurança e, ao mesmo tempo, não poder alterá-lo mais tarde (lembre-se da ABI).

Como o C ++ decidiu torná-lo estável, todas essas sugestões devem ser destruídas e queimadas. Eu não gostaria de ser destruído, mas isso deve ser feito.

Mas eles ainda não o fazem.

Na melhor das hipóteses, não cometeremos erros e padronizaremos o estado atual das coisas em uma das novas versões do C ++ e deixaremos que tudo se decomponha lentamente, pois não será possível corrigi-lo (no caso do Networking TS, parece que não conseguimos alterar nada, portanto, teremos que padronizar o que existia há dez anos, e é claro que a biblioteca ainda pode ser significativamente melhorada, mas vamos deixar essa história para outra época).

Mas é claro que vamos cometer muitos, muitos erros.

>> Ólafur Waage @olafurw
( , )

, !

. , ( : , , )?

Hyrum Wright @hyrumwright
, , . — , .

Alguns erros são cometidos intencionalmente, pois são trade-offs, enquanto outros passam despercebidos por muitos anos.

O tempo passa, mas a biblioteca padrão fica parada. As compensações feitas anteriormente estão gradualmente começando a nos incomodar e depois se tornam verdadeiros “gargalos” no código existente.

Algumas coisas são realmente impossíveis de mudar, pois estão incorporadas na API. Todos nós temos uma idéia de quão difícil é alterar uma API existente. Mas parte do código ainda pode ser corrigido e aprimorado se pudermos quebrar a ABI.

O C ++ ainda estará disponível nos próximos 40 anos. Se não pudermos perceber a necessidade de alterá-lo de maneira imprevisível a qualquer momento, o único movimento certo será não jogar esse jogo em princípio.

Todo mundo sabe que um contêiner associativo padrão é relevante para uso há menos de dez anos. Mas por que achamos que propostas maiores no padrão terão mais sucesso?

Sua oferta ao padrão será destruída, a minha será destruída da mesma maneira.

Um comitê pode, em princípio, quebrar uma ABI?


Muitos têm certeza de que o comitê não pode, em princípio, tomar essa decisão, porque os desenvolvedores da biblioteca simplesmente a ignoram. Tudo isso se assemelha dolorosamente à queda de braço, na qual o comitê decidiu não jogar.

Mas o fato é que os desenvolvedores de qualquer produto têm seus próprios usuários. Os usuários são aqueles que, em primeiro lugar, precisam entender quais compensações lhes são impostas.

Muitas pessoas confiam na ABI acidentalmente, sem fazer uma escolha informada. Muitas pessoas também confiam na estabilidade porque, é claro, todo mundo quer confiar nela. Mas, como qualquer outra coisa, a estabilidade tem um preço, e agora todo o ecossistema C ++ paga por isso.

All Articles