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 deint32_t
como identificador. - Usa
base::TokenType<TagType>
en lugar de unbase::UnguessableToken
no específico. - Usa una clase enum en lugar de un bool
(por ejemplo,
kForReload
,kNotForReload
en lugar detrue
,false
). - Reemplaza otros tipos no específicos por
base::StrongAlias<TagType, SomeWrappedType>
.