Chronicle 24 של Chromium: StrongAlias , IdType ו-TokenType

פרק 24: מאת Lucasz Anforowicz in Bellevue, WA (אוגוסט 2021)
הפרקים הקודמים

מצאתם את הבאג בקוד שלמטה? האם היית רואה את באג בבדיקת קוד, כשמעיינים רק באתר הטלפוני?

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

לפעמים אותו סוג מייצג ערכים מדומיינים לא תואמים. זה קורה בדרך כלל בסוגי נתונים לא ספציפיים, כמו מספרים שלמים או מחרוזות. הדוגמה שלמעלה ממחישה איך זה יכול לגרום לבאגים. למרבה המזל, //base של Chromium מאפשר להציג בקלות סוגים ייחודיים וברורים:

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

המהדר (compiler) רואה שהסוגים לא תואמים, כי יש להם "תג" אחר מהסוג הזה. StrongAlias מקבל כל סוג כ'תג' מהסוג הזה. בדוגמה מצוין שה'תג' אינו זקוק אפילו להגדרת סוג בכל מקום - הצהרה קודמת לגבי מחלקה שלא קיימת עובדת כמו שצריך.

בעתיד, במקום להשתמש בסוג לא ספציפי (לדוגמה: בוליאני, מספר Int או מחרוזת), לכן כדאי לשקול את החלופות הבאות:

  • צריך להשתמש ב-base::IdType32<TagType> במקום ב-int32_t כמזהה.
  • צריך להשתמש ב-base::TokenType<TagType> במקום ב-base::UnguessableToken לא ספציפי.
  • צריך להשתמש במחלקה 'טיפוסים בני מנייה (enum)' במקום בבוליאני (לדוגמה, kForReload, kNotForReload במקום true, false).
  • מחליפים סוגים אחרים לא ספציפיים ב-base::StrongAlias<TagType, SomeWrappedType>.