Chromium Chronicle #24: strongAlias, IdType e TokenType

Episódio 24:por Łukasz Anforowicz em Bellevue, WA (agosto de 2021)
Episódios anteriores

Consegue identificar o bug no código abaixo? Você veria o bug em uma revisão de código ao analisar apenas o local de chamadas?

Token CreateToken(int command_data, int buffer_id);
...
auto token = CreateToken(GetCommandBufferId(), GetCommandData());

Às vezes, o mesmo tipo pode representar valores de domínios incompatíveis. Isso geralmente acontece para tipos de dados não específicos, como números inteiros ou strings. O exemplo acima ilustra como isso pode causar bugs. Felizmente, o //base do Chromium facilita a introdução de tipos explícitos e distintos:

#include "base/types/strong_alias.h"

// The first template argument of StrongAlias is a "tag" type.
// The "tag" type is used to distinguish between different
// StrongAlias types.
using CommandData = base::StrongAlias<class CommandDataTag, int>;
using CommandBufferId = base::StrongAlias<class CommandBufferIdTag, int>;

Token CreateToken(CommandData command_data, CommandBufferId buffer_id);

Tipos separados melhoram a legibilidade. Além disso, o StrongAlias detecta misturas de tipo no tempo de compilação:

test.cc:456:16: error: no matching function for call to 'CreateToken'
  auto token = CreateToken(GetCommandBufferId(), GetCommandData());
               ^~~~~~~~~~~
test.cc:123:7: note: candidate function not viable: no known conversion from
'StrongAlias<class CommandBufferIdTag, [...]>' to
'StrongAlias<class CommandDataTag, [...]>' for 1st argument
Token CreateToken(CommandData command_data, CommandBufferId buffer_id);
      ^

O compilador vê que os tipos são incompatíveis, porque eles têm um tipo de "tag" diferente. StrongAlias aceita qualquer tipo como o tipo "tag". O exemplo mostra que o tipo "tag" não precisa de uma definição de tipo em nenhum lugar. Uma declaração de encaminhamento de uma classe inexistente funciona bem.

No futuro, em vez de um tipo não específico (por exemplo, um booleano, um int ou uma string), considere estas alternativas:

  • Use base::IdType32<TagType> em vez de usar int32_t como um identificador.
  • Use base::TokenType<TagType> em vez de um base::UnguessableToken não específico.
  • Use uma classe de enumeração em vez de um booleano (por exemplo, kForReload, kNotForReload em vez de true, false).
  • Substitua outros tipos não específicos por base::StrongAlias<TagType, SomeWrappedType>.