Chromium Chronicle #24: StrongAlias, IdType 및 TokenType

에피소드 24: 작성자: 루카스 안포로비츠, 워싱턴주 벨뷰 (2021년 8월)
이전 에피소드

아래 코드에서 버그를 찾을 수 있나요? 호출 사이트만 살펴볼 때 코드 검토에서 버그 버그가 표시되나요?

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는 모든 유형을 '태그' 유형으로 허용합니다. 이 예는 '태그' 유형이 어디에도 유형 정의가 필요하지 않음을 보여줍니다. 존재하지 않는 클래스의 인플레이스 전방 선언은 잘 작동합니다.

앞으로는 특정 유형 (예: 부울, 정수, 문자열) 대신 다음과 같은 대안을 고려해 보세요.

  • int32_t를 식별자로 사용하는 대신 base::IdType32<TagType>를 사용합니다.
  • 구체적이지 않은 base::UnguessableToken 대신 base::TokenType<TagType>를 사용합니다.
  • 부울 대신 enum 클래스를 사용합니다(예: true, false 대신 kForReload, kNotForReload).
  • 기타 특수 유형을 base::StrongAlias<TagType, SomeWrappedType>로 대체합니다.