Chromium Chronicle #24: StrongAlias, IdType et TokenType

Épisode 24:Łukasz Anforowicz à Bellevue, Washington (août 2021)
Épisodes précédents

Pouvez-vous repérer le bug dans le code ci-dessous ? Voudriez-vous le bug lors d'une revue de code, lorsque vous consultez uniquement le site d'appel ?

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

Le même type peut parfois représenter des valeurs provenant de domaines incompatibles. Cela se produit généralement pour des types de données non spécifiques tels que les entiers ou les chaînes. L'exemple ci-dessus montre comment cela peut provoquer des bugs. Heureusement, le fichier //base de Chromium permet d'introduire facilement des types explicites et distincts:

#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);

Les types distincts améliorent la lisibilité. De plus, StrongAlias détecte les combinaisons de types au moment de la compilation:

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);
      ^

Le compilateur voit que les types sont incompatibles, car ils ont un "tag" différent de mots clés. StrongAlias accepte n'importe quel type comme "tag" de mots clés. Cet exemple montre que le "tag" n'a même pas besoin d'une définition de type où que ce soit, la déclaration directe sur place d'une classe inexistante fonctionne correctement.

À l'avenir, au lieu d'un type non spécifique (par exemple, une valeur booléenne, un entier ou une chaîne), envisagez ces alternatives:

  • Utilisez base::IdType32<TagType> au lieu d'utiliser int32_t comme identifiant.
  • Utilisez base::TokenType<TagType> au lieu d'un base::UnguessableToken non spécifique.
  • Utiliser une classe d'énumération au lieu d'une valeur booléenne (par exemple, kForReload, kNotForReload au lieu de true, false).
  • Remplacez d'autres types non spécifiques par base::StrongAlias<TagType, SomeWrappedType>.