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é unbase::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>
.