domingo, 11 de diciembre de 2011

Boost.Fusion: introspección en tiempo de compilación para estructuras en C++

Una de las librerías que más me gusta de las Boost C++ Libraries es la Boost.Fusion. No voy a entrar en detalle en lo que ofrece esta librería; básicamente permite el manejo de tuplas de elementos de distintos tipos.

Lo bueno de las tuplas que ofrece esta librería son las meta-funciones que ofrecen introspección en tiempo de compilación sobre estas tuplas. El disponer de esta introspección permite escribir código genérico sea cual sea el número y tipo de los elementos de estas tuplas.

La característica que más me gusta de esta librería es que permite poder adaptar estructuras convencionales de C++ para ser utilizadas como lo que realmente son: tuplas de elementos de distintos tipos. De esta forma, podemos utilizar las meta-funciones de esta librería sobre estructuras y así escribir código genérico. Creo que el poder adaptar estructuras para poder tener cierta introspección -siempre en tiempo de compilación- cubre una de las carencias principales del lenguaje C++.

Esta característica la he usado en varios proyectos. Uno de ellos es CORBASIM, donde se utiliza para generar automáticamente -en tiempo de compilación- formularios para introducir datos. También se utiliza para serializar estas estructuras en formato JSON.

Lo malo de esta característica, es que para poder utilizarla hay que definir dos veces la estructura: una -la propia estructura-, y otra con la macro BOOST_FUSION_ADAPT_STRUCT. Es decir, escribir dos veces la misma información semántica. En CORBASIM esto no supone ningún problema, ya que todo el código es generado a partir de ficheros IDL. Pero en otros ámbitos donde no hay un DSL ni código generado de por medio, esta duplicidad es un poco incómoda. La falta de esta introspección de por sí en el lenguaje es -en mi opinión- la mayor de sus carencias.

Para intentar cubrir esta carencia estaría bien disponer de una herramienta que realice esta adaptación de forma automática, generando código C++ adicional a partir de código C++. Esto no sería muy difícil; bastaría recorrer el AST del código en el que se definen las estructuras que queremos adaptar. El AST se puede recorrer por ejemplo con un plugin de GCC, solo hay que echarle tiempo. En una prueba rápida, he conseguido esbozar esta herramienta utilizando Dehydra.

Aunque Dehydra permite recorrer el AST mediante código JavaScript con el fin de implementar validadores de código C++, también se podría utilizar para generar automáticamente este código adicional. El código JavaScript del esbozo que he realizado con Dehydra para generar este código es tan sencillo como el que sigue:

function getHeader(name)
{
    return name.replace('::','_').toUpperCase() + '_ADAPTED';
}

function process_type(type)
{
    if (type.kind == "struct" && !type.typedef 
            && type.members.length > 0)
    {
        header = getHeader(type.name);
        print('#ifndef ' + header);
        print('#define ' + header);

        print('// Generated code for ' + type.name + 
                ' defined in ' + type.loc);
        // Uso de Boost.Fusion
        print('BOOST_FUSION_ADAPT_STRUCT (');
        print('\t' + type.name + ',');
        for each(let m in type.members)
        {
            print('\t(' + m.type.name + ', ' + m.shortName+')');
        }
        print(')');
        print('');

        print('#endif // ' + header);
        print('');
    }
}


Esta herramienta me parece interesante para poder generalizar parte del trabajo realizado en CORBASIM, haciéndolo independiente de CORBA. Extenderé la idea :)

No hay comentarios:

Publicar un comentario