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, se esamini solo il sito di chiamata?

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

A volte lo stesso tipo può rappresentare valori di domini non compatibili. Questo di solito accade per tipi di dati non specifici, come numeri interi o stringhe. L'esempio precedente illustra come ciò possa causare dei bug. Fortunatamente, //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 distinti migliorano la leggibilità. Inoltre, StrongAlias rileva i problemi relativi ai 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 tipo di "tag" diverso. StrongAlias accetta qualsiasi tipo come tipo di "tag". L'esempio mostra che il tipo "tag" non ha nemmeno bisogno di una definizione del tipo da nessuna parte; una dichiarazione "in-place" di una classe inesistente va bene.

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

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