The Chromium Chronicle n. 24: StrongAlias, IdType e TokenType

Episodio 24: di Łukasz Anforowicz a Bellevue, WA (agosto 2021)
Puntate precedenti

Riesci a individuare il bug nel codice qui sotto? Vedresti il bug in una revisione del codice, solo quando si guarda il sito di chiamata?

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

Lo stesso tipo a volte può rappresentare valori di domini incompatibili. In genere questo accade per tipi di dati non specifici come numeri interi o stringhe. L'esempio precedente illustra come ciò può causare bug. Fortunatamente, l'//base di Chromium semplifica l'introduzione di tipi espliciti e distinti:

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

I tipi separati migliorano la leggibilità. Inoltre, StrongAlias rileva le discrepanze dei tipi al momento della compilazione:

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

Il compilatore vede che i tipi non sono compatibili, perché hanno un "tag" diverso di testo. StrongAlias accetta qualsiasi tipo come "tag" di testo. L'esempio mostra che il "tag" tipo non ha bisogno nemmeno di una definizione, è consentito dichiarare una classe inesistente.

In futuro, invece di un tipo non specifico (ad esempio un bool, un int, una stringa), prendi in considerazione queste alternative:

  • Usa base::IdType32<TagType> anziché int32_t come identificatore.
  • Usa base::TokenType<TagType> anziché un base::UnguessableToken non specifico.
  • Utilizza una classe enum anziché un bool (ad esempio, kForReload, kNotForReload anziché true, false).
  • Sostituisci altri tipi non specifici con base::StrongAlias<TagType, SomeWrappedType>.