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

פרק 24: מאת לוקאש אנפורוביץ' בבלוויו, וושינגטון (אוגוסט 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);
      ^

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

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

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