Chromium Chronicle #24: StrongAlias、IdType、TokenType

エピソード 24: ワシントン州ベルビューでの LoadBalancersz Anforowicz(2021 年 8 月)
前のエピソード

以下のコードでバグを見つけます。Cloud Shell の バグ コードのレビューで コールサイトだけを見るとどうでしょうか。

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

同じ型が、互換性のないドメインからの値を表すことがあります。 これは通常、整数や文字列など、具体的でないデータ型で発生します。 上記の例は、これによりバグがどのように発生するかを示しています。 幸い、Chromium の //base を使用すると、明示的な異なる型を簡単に導入できます。

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

型を分離することで、読みやすくなります。 さらに、StrongAlias はコンパイル時に型の混在をキャッチします。

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

コンパイラは型に互換性がないことを認識し、 なぜなら「タグ」が異なるためですあります。 StrongAlias は、任意の型を「タグ」として受け入れます。あります。 この例では、「タグ」が型の定義が特に必要なく、 存在しないクラスをインプレース前方宣言しても問題ありません。

将来的には、特定の型(bool、int、string など)ではなく、 次の代替手段を検討してください。

  • 識別子として int32_t を使用する代わりに、base::IdType32<TagType> を使用します。
  • 不特定の base::UnguessableToken ではなく、base::TokenType<TagType> を使用します。
  • ブール値の代わりに列挙型クラスを使用する (例: truefalse ではなく kForReloadkNotForReload)。
  • 他の非特定型を base::StrongAlias<TagType, SomeWrappedType> に置き換えます。