Chromium Chronicle n.o 24: StrongAlias, IdType y TokenType

Episodio 24: de Łukasz Anforowicz en Bellevue, WA (agosto de 2021)
Episodios anteriores

¿Puedes detectar el error en el siguiente código? ¿Verías el error en una revisión de código si solo observas el sitio de llamada?

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

A veces, el mismo tipo puede representar valores de dominios incompatibles. Esto suele suceder con tipos de datos no específicos, como números enteros o strings. En el ejemplo anterior, se ilustra cómo esto puede causar errores. Afortunadamente, //base de Chromium facilita la introducción de tipos explícitos y distintos:

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

Los tipos separados mejoran la legibilidad. Además, StrongAlias detecta combinaciones de tipos en el tiempo de compilación:

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

El compilador detecta que los tipos son incompatibles porque tienen un tipo de "etiqueta" diferente. StrongAlias acepta cualquier tipo como el tipo "etiqueta". En el ejemplo, se muestra que el tipo "tag" ni siquiera necesita una definición de tipo en ningún lugar; una declaración directa in situ de una clase inexistente funciona bien.

En el futuro, en lugar de usar un tipo no específico (por ejemplo, un bool, un int o una string), ten en cuenta estas alternativas:

  • Usa base::IdType32<TagType> en lugar de int32_t como identificador.
  • Usa base::TokenType<TagType> en lugar de un base::UnguessableToken no específico.
  • Usa una clase enum en lugar de un bool (por ejemplo, kForReload, kNotForReload en lugar de true, false).
  • Reemplaza otros tipos no específicos por base::StrongAlias<TagType, SomeWrappedType>.