.NET 4 y Web Semántica: el inicio de un romance

Uno de los Principios de Diseño (para una arquitectura web) de Tim Berners-Lee es el Principio de la Menor Potencia (Principle of Least Power). Referente a los lenguajes de programación plantea que “… En la actualidad debemos tomar en consideración una razón para escoger la solución menos potente en lugar de la más poderosa: mientras menos potente sea el lenguaje, más puedes lograr con los datos almacenados en el lenguaje …”.

Durante muchos años ha ocurrido cierta “discriminación” en círculos elitistas de programación hacia los lenguajes de tipificación dinámica (ej. Visual Basic anterior a VB.NET, ASP, Javascript), aquellos en los cuales el chequeo de tipos ocurre en tiempo de ejecución, opuesto a los de tipificación estática (ej. C, C++, C#, Java), para los que el chequeo de tipos se realiza durante la compilación. Lo mismo sucede con otras clasificaciones de los lenguajes como tipificación fuerte vs débil, interpretados vs compilados, entre otras. En estas élites se consideran “verdaderos programadores” a los que trabajan en lenguajes compilados y tipificados estáticamente, leáse cualquier variante con llaves { }. Para muchos, los lenguajes sin tipos o con un comodín como el Variant de Visual Basic, son algo así como demonios malignos, y realmente la asignación de un tipo de datos a cada variable y el chequeo en el proceso de compilación de su uso correcto, evita un gran número de problemas y errores durante la ejecución. Un comentarista del post I like strong typing and compilation errors plantea muy acertadamente que “la tipificación fuerte y los errores de compilación (entre ellos los relativos a la tipificación estática) son unidades de prueba (unit tests) implícitas que nunca será necesario escribir, opuesto a cuando se usa un lenguaje con tipificación dinámica, en el cual es obligatorio construir estas unidades de prueba si deseamos cierto nivel de protección contra errores de regresión”.

Pero bueno, estos debates casi que apasionados han perdurado durante mucho tiempo y seguirán así por mucho más. En la práctica, la elección del lenguaje para un proyecto depende mucho de las preferencias y/o dominio del equipo y de la misma naturaleza del trabajo en cuestión. He visto muchos proyectos implementados en Visual Basic con una calidad y diseño impecables y otros hechos en C# realmente vergonzozos.

Finalmente, aparece la version 4 de .NET y con ella la posibilidad de usar variables dinámicas en C# y el resto de los lenguajes compatibles. Muchos interpretan esto como un paso atrás, un regreso al viejo Variant del viejo Visual Basic.

Si ha leído hasta aquí, ya se estará preguntando: qué tiene que ver todo lo anterior con el Principio de la Menor Potencia y con el título del post? Muy sencillo, actualmente las tecnologías semánticas se encuentran muy cerca de alcanzar la “masa crítica” de popularidad y con ello los “lenguajes discriminados” o mejor, los conceptos en los están basados, se convierten en poderosas herramientas para el tratamiento de las estructuras de datos semánticas. Pensemos en XML, RDF, OWL, que permiten representar objetos eminentemente dinámicos; resulta bastante díficil encasillarlos en un sistema de tipos estáticos. Con la introducción de las características dinámicas en .NET 4, evidentemente Microsoft está abriendo el camino a los desarrolladores hacia la Web Semántica (además de otras aplicaciones, por supuesto). Sin embargo, creo que aún queda mucho camino por recorrer.

En los últimos días he estado experimentando un poco con el “nuevo dinamismo” de C#, en parte motivado por la “asignatura pendiente” de mi post Consultando RDF con SPARQL en C# (2da parte), y con la esperanza de que el problema presentado allí sería ahora mucho más simple de resolver. Concretamente, se trata de construir progresivamente una lista genérica de objetos de una clase diferente en cada ejecución; por tanto debe ser una clase dinámica. La definición de la clase en si, proviene del resultado de una consulta SPARQL a un almacén RDF y consiste de un grupo de nombres de variables (definidas por el usuario en el texto de la consulta). La ejecución de la consulta retorna en cada paso los nombres de estas variables (miembros de la clase dinámica) y sus valores, conformando ambos un nuevo objeto para agregar a la lista. Una vez obtenidos todos los resultados se desea mostrarlos en una tabla (DataGridView) empleando las capacidades de enlace de datos (data binding).

System.Dynamic es el ensamblado que permite el uso de las características dinámicas y DynamicObject es la clase base, aunque es común iniciar los experimentos con la clase ExpandoObject que hereda de DynamicObject e implementa funcionalidad real. Expando permite la utilización de miembros y funciones dinámicas, o sea, en tiempo de ejecución, que no se han definido anteriormente en compilación.

dynamic obj = new ExpandoObject();
obj.Titulo = ".NET 4 y Web Semántica: el inicio de un romance";
obj.Autor = "johnbarquin";

// ... y hasta se pueden anidar

obj.Autor.Nombre = "Juan Pedro";
obj.Autor.Apellido = "Barquin";

Esta clase resulta muy cómoda para la representación de objetos de naturaleza anidada y con niveles de profundidad como los generados a partir de un XML y su amplia gama de derivados (RDF/XML es una de las serializaciones más populares de RDF). En casi todos los artículos introductorios se muestran ejemplos en los cuales se usan nombres de miembros conocidos de antemano, ej. obj.Autor.Apellido, obj.Titulo. Resultaría pues interesante, ver cómo añadir miembros realmente dinámicos, por ejemplo, los nombres de variables en cada ejecución de una consulta SPARQL. Profundizando un poco, descubrimos que ExpandoObject implementa la interfaz IDictionary<string, object> para la “simulación” de los miembros dinámicos; ello significa que, aunque de forma no tan agradable a la vista, podemos añadir miembros nuevos así:

dynamic obj = new ExpandoObject();
string nombreMiembro = Obtener_el_nombre_de_alguna_forma();
string valorMiembro = Obtener_el_valor_de_otra_forma();
((IDictionary&lt;string, object&gt)obj).Add( nombreMiembro, valorMiembro );

Retornando al problema de Consultando RDF con SPARQL en C# (2da parte), usando ExpandoObject, nuestra clase que recibe los resultados de la consulta SPARQL quedaría así:

public class DynamicObjectsResultSink : QueryResultSink
{
    public List&ltobject&gt queryResults;

    public override void Init(Variable[] variables)
    {
        base.Init(variables);

        // Vaciar la lista, dejarla preparada para recibir los objetos reales
        queryResults = new List&ltobject&gt();
        queryResults.Clear();
    }

    public override bool Add(VariableBindings result)
    {
        dynamic objDinamico = new ExpandoObject();

        for (int i = 0; i < result.Variables.Count; i++)
            ((IDictionary<string, object>)objDinamico).Add(result.Variables[i].LocalName, result[result.Variables[i]].ToString());

        queryResults.Add(objDinamico);

        return true;
    }
}

y en una forma de Windows (WinForm) se pudiera usar la siguiente función para realizar la consulta SPARQL y llenar el DataGridView gridResults con los resultados:

public void QueryDataSourceDynamicClass(string url, string consulta)
{
    try
    {
        SparqlHttpSource almacen = new SparqlHttpSource(url);
        SparqlEngine query = new SparqlEngine(consulta);
        DynamicObjectsResultSink results = new DynamicObjectsResultSink();
        query.Run(almacen, results);

        // NO FUNCIONA
        gridResults.DataSource = results.queryResults;
    }
    catch (Exception ex)
    {
        MessageBox.Show("Error procesando query: " + ex.Message);
    }
}

Sin embargo, luego de ejecutar este código, el grid permanece vacío. La explicación es muy simple: los controles para aplicaciones WinForm realizan el data binding internamente usando System.Reflection y Reflection (hasta el día de hoy) solo funciona para clases definidas estáticamente, creadas en tiempo de compilación, por tanto es incapaz de reconocer los miembros públicos definidos de forma dinámica. Quizás esta situación cambie en alguna actualización futura del framework o quizás no, pues Microsoft está promoviendo hace algún tiempo el uso de Windows Presentation Foundation (WPF) para aplicaciones desktop.

Y WPF introduce un nuevo modelo avanzado de data binding a través del cual es posible lograr el enlace con los miembros dinámicos, no tan fácil como desearíamos, pues hay que definir las columnas del grid manualmente:

public void QueryDataSourceDynamicClass(string url, string consulta)
{
    try
    {
        SparqlHttpSource almacen = new SparqlHttpSource(url);
        SparqlEngine query = new SparqlEngine(consulta);
        DynamicObjectsResultSink results = new DynamicObjectsResultSink();
        query.Run(almacen, results);

        // Crear las columnas
        foreach (var c in ((IDictionary<string, object>)results.queryResults[0]).Keys)
            gridResults.Columns.Add(new DataGridTextColumn
            {
                Header = c,
                Binding = new Binding(c)
            });

        gridResults.AutoGenerateColumns = false;
        gridResults.ItemsSource = results.queryResults;
    }
    catch (Exception ex)
    {
        MessageBox.Show("Error procesando query: " + ex.Message);
    }
}

Con esto tenemos al menos dos opciones para resolver un problema similar:

  1. El método usado en el post Consultando RDF con SPARQL en C# (2da parte) que funciona en WinForms .NET 3, luego no usa System.Dynamic pero si requiere la clase System.Linq.Dynamic.DynamicExpression que no forma parte de .NET, sino fue extraída de los ejemplos para LINQ presentados por Microsoft para la versión CTP de Visual Studio 2008; una clase bien compleja por cierto.
  2. El método expuesto en este post usando ExpandoObject pero usando WPF, lo cual no es una opción si es parte de un proyecto mayor que ya esta desarrollado sobre WinForms.

Las primeras impresiones con System.Dynamic me resultan por una parte muy favorables ya que facilitan sintácticamente el trabajo con las complejas y cambiantes estructuras de los objetos semánticos. Por otra parte, aún no resuelve problemas relativamente simples como el expuesto en el ejemplo anterior. Alexandra Rusina muestra en el post Dynamic in C# 4.0: Introducing the ExpandoObject una serie de ejemplos prácticos y elementos que indican que ExpandoObject es más que síntaxis mejorada, a saber, que implementa la intefaz INotifyPropertyChanged lo cual permite mejor control sobre las propiedades, y la posibilidad de definir eventos.

Personalmente, por supuesto que seguiré manipulando estas nuevas características y probándolas en aplicaciones reales para llegar a comprender si son realmente cambios radicales en el framework o simplemente azúcar sintáctica para simplificar la programación. Y por otro lado, seguir de cerca este romance entre .NET y Web Semántica, y verificar hasta donde llega y hasta donde nos deja llegar como desarrolladores.

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: