Conceptos sobre
programación funcional y las mejoras sintácticas de C# 3.0 y VB 9.0
Hola niños ¡Estamos a unas horas del 2008! Espero que se
encuentren muy bien y Santa Claus les haya traído algo más que nuevos depósitos
de grasa en su puerquecito. Me quería despedir del 2007, con un artículo para
toda la banda geek que pulula por la red. Deseo sinceramente que el año
venidero esté lleno de Salud, Dinero y Sexo, o como dicen los cursis “Amor”.
¡No todo es computadoras niños, salgan a la calle y busquen a quien amar, puaf,
escupí lengua!
En fin, al diablo con mi intento de ser gracioso. En este
post podrán encontrar la mayoría de las características sintácticas nuevas que
encontramos en los lenguajes de programación que salieron con la versión de
Visual Studio 2008 (Me refiero a C# 3.0 Y VB 9.0) , o lo que es lo mismo en
este post hablaré de los cambios sintácticos que tienen los lenguajes de
programación de Microsoft para dar soporte a la tecnología denominada LINQ,
además de un breviario sobre programación funcional.
Es importante conocer estos detalles toda vez que si
ignoramos su funcionamiento es muy posible que no podamos explotar cabalidad la
gran cantidad de características que tenemos a nuestra disposición con los
lenguajes.
Bueno pues ahora comencemos
pues a recorrer las nuevas características que estoy seguro le serán muy
interesantes.
1) Inferencia de tipos
Una de las principales características encontramos en .NET
3.5 es la inferencia de tipos,
La inferencia de tipos es fundamental para el funcionamiento
de la tecnología LINQ, toda vez que al momento de hacer un query, no es posible
saber el tipo de datos de la colección
que regresará el mismo query.
Esta característica nos permite utilizar la palabra
reservada var
en C# o Dim en conjunto con Option Infer On en Visual Basic para declarar cualquier
variable antes de un query o bien declararla en línea e inicializarla al mismo
tiempo. Automáticamente el compilador de los lenguajes asumirá el tipo de datos
asignado en la inicialización o en la ejecución del query y hará que la
variable sea fuertemente tipeada durante el resto de la ejecución del programa;
como podemos apreciar esto difiere totalmente el funcionamiento Javascript o del
mismo Visual Basic 6.0 con su tipo de
datos Variant, ya que en estos lenguajes es posible cambiar dinámicamente de
tipo de datos, con su correspondiente pérdida de desempeño y la mayor
probabilidad de incurrir en errores de programación en tiempo de ejecución. En
.NET 3.5 esto NO se da debido a que la
inferencia equipos se hace en tiempo de compilación y no en tiempo de ejecución
como sucede con VB 6.0
Para mostrar esto comenzaremos con crear una simple clase de
discos
C#
public
class Disco
{
public
int Id;
public
string Titulo;
public
string
Interprete;
public
string Genero;
public
double Precio;
}
VB
Public Class
Disco
Public
Id As Integer
Public
Titulo As String
Public Interprete As
String
Public Genero As
String
Public Precio As
Double
End Class
Posteriormente haremos uso de la inferencia de tipos de la
siguiente manera
C#
var lobjDisco=new
Disco() ;
lobjDisco.Genero = "Cumbia";
lobjDisco.Interprete = "Laura Leon";
lobjDisco.Id = 1;
lobjDisco.Titulo = "Noches de cumbia";
MessageBox.Show(lobjDisco.Genero);
VB
Option Infer On
Dim lobjDisco = New
Disco
lobjDisco.Genero = "Cumbia"
lobjDisco.Interprete = "Laura Leon"
lobjDisco.Id = 1
lobjDisco.Titulo = "Noches de cumbia"
lobjDisco.Precio = 230
MsgBox(lobjDisco.Genero)
El código del ejemplo anterior mostrara correctamente el
género del disco si somos algo curiosos podemos tratar de asignar a la variable
lobjDisco un objeto que no se del
tipo disco y podemos ver cómo el compilador nos dirá una grosería toda vez que
la variable es fuertemente tipeada.
2) Inicializadores de objetos.
Esta azúcar sintáctica es realmente útil debido a que
en .NET 2.x y anteriores es necesario generar un constructor sobrecargado si
queremos inicializar las variables de un objeto al momento de que es
instanciado, así sí tenemos 20 variables es necesario generar 20 constructores
(o muchos más si las combinamos) para
poder inicializar las propiedades o campos de nuestro objeto lo cual se traduce
en una gran pérdida de tiempo al momento de estar programando. Con esta
característica sin modificar el código previo de definición de la clase disco
podemos utilizar la siguiente sintaxis que nos permitirá inicializar las
propiedades o campos del objeto:
C#
lobjDisco = new
Disco { Id = 2, Genero = "Trance", Interprete = "Armin Van Buuren" , Precio=300};
VB
lobjDisco = New Disco With {.Id =
2, .Genero = "Trance", .Interprete
= "Armin Van Buuren", .Precio =
130}
3) Tipos anónimos
Los tipos anonimos nos permiten generar tipos al
vuelo sin necesidad de declarar explícitamente la estructura y la definición de
la clase. Esto se usa principalmente cuando queremos hacer algún cálculo o
queremos generar un nuevo tipo basado en el resultado que nos pudiera llegar a
dar un query de LINQ. En la misma manera que sucede con inferencia de tipos los
tipos anónimos son creados en tiempo de compilación y no en tiempo de ejecución
lo que se traduce en que no hay pérdida de rendimiento de la aplicación cabe
señalar que los miembros de los tipos anónimos son de solo lectura
C#
var
lobjDisquera = new { Nombre = "Discos Maic" };
var
lobjDisquera2 = new { Nombre = "Discos Lucha" };
var
lobjDisquera3 = lobjDisquera2;
MessageBox.Show(lobjDisquera3.Nombre);
VB
Dim
lobjDisquera = New With
{.Nombre = "Discos Maic"}
Dim
lobjDisquera2 = New With
{.Nombre = "Discos Lucha"}
Dim
lobjDisquera3 = lobjDisquera2
MsgBox(lobjDisquera3.Nombre)
4) Métodos de
extension
Sabemos nosotros que en el mundo de. Net es possible
utilizar técnicas como la herencia desde una clase abstracta y generar métodos
adicionales por una clase concreta para extender la funcionalidad de una clase
base, sin embargo muchas veces para lograr esto es necesario re compilar el
tipo de datos original y derivado además de que es necesario tener los permisos
correspondientes en la clase base para poder extender exitosamente el tipo.
Los métodos de extensión nos permiten agregar
funcionalidad adicional a una clase base sin necesidad de generar subclases.
Cabe señalar que los métodos de extensión deben de ser estáticos.
Para definir un método de extensión utilizamos la
siguiente sintaxis
C#
public
static class Extensiones
{
public
static void
MostrarPrecio(this Disco
pobjDisco)
{
MessageBox.Show(pobjDisco.Precio.ToString());
}
}
VB
Module Extensiones
<Extension()> Public Sub MostrarPrecio(ByVal pobjDisco As
Disco)
MsgBox(pobjDisco.Precio)
End Sub
End Module
Una vez que nosotros implementamos el código anterior
podemos ver que el tipo disco ahora tienen método de extensión denominado
MostrarPrecio y podemos invocarlo como cualquier otro método.
Cuando nosotros utilizamos LINQ, al momento de hacer
un query, el objeto resultante de este query tiene una gran cantidad de métodos
de extensión añadidos que nos permiten utilizar la funcionalidad de los
operadores de query como group by, order by, count, average etc., De ahí la
importancia de conocer su correcto funcionamiento.
5) Sintaxis de
Query (LINQ)
LINQ como tal es una serie de tecnologías que nos
permiten utilizar sentencias parecidas a SQL para manipular los objetos de la
misma manera que lo hacemos con tablas del paradigma la relaciónal.
La tecnología LINQ esta dividida en diferentes
sabores de acuerdo a su aplicación.
LINQ to
Objects: es la tecnología que examinaremos con el siguiente código
cualquier objeto que sea una colección dentro de. Net es susceptible a que se
le haga un cuello con LINQ y generará a partir de ella un nuevo tipo de datos
obteniendo los resultados del query
C#
lobjDiscos.Add(new Disco{Id =
3,Genero="Pop",Interprete="Fey", Titulo="Vertigo",
Precio=120});
lobjDiscos.Add(new Disco { Id =
4, Genero = "Pop", Interprete = "Simply Red", Titulo = "Sunrise", Precio = 320 });
lobjDiscos.Add(new Disco { Id =
5, Genero = "Rock", Interprete = "Guns n Roses", Titulo = "Use your ilution", Precio = 220 });
lobjDiscos.Add(new
Disco { Id = 6, Genero = "Dance", Interprete = "Gigi Dagostino", Titulo = "L amour tojours", Precio = 99 });
lobjDiscos.Add(new Disco { Id =
7, Genero = "Clasica", Interprete
= "Haendel", Titulo = "Mesias", Precio = 410 });
lobjDiscos.Add(new Disco { Id =
8, Genero = "Hip Hop", Interprete
= "Linkin Park", Titulo = "Meteora", Precio = 60 });
var
lobjDiscosSeleccionados = from
lobjSeleccionDiscos in lobjDiscos
where lobjSeleccionDiscos.Precio > 300
orderby lobjSeleccionDiscos.Id
select new
{lobjSeleccionDiscos.Titulo, lobjSeleccionDiscos.Precio};
foreach
(var lobjDisc in
lobjDiscosSeleccionados)
{
MessageBox.Show(lobjDisc.Titulo
+ " - " +lobjDisc.Precio);
}
VB
lobjDiscos.Add(New
Disco With {.Id = 3, .Genero = "Pop", .Interprete = "Fey", .Titulo = "Vertigo", .Precio = 120})
lobjDiscos.Add(New
Disco With {.Id = 4, .Genero = "Pop", .Interprete = "Simply Red", .Titulo = "Sunrise", .Precio = 320})
lobjDiscos.Add(New Disco With {.Id =
5, .Genero = "Rock", .Interprete =
"Guns n Roses", .Titulo = "Use your ilution", .Precio = 220})
lobjDiscos.Add(New Disco With {.Id =
6, .Genero = "Dance", .Interprete
= "Gigi Dagostino", .Titulo = "L amour tojours", .Precio = 99})
lobjDiscos.Add(New Disco With {.Id =
7, .Genero = "Clasica",
.Interprete = "Haendel", .Titulo =
"Mesias", .Precio = 410})
lobjDiscos.Add(New Disco With {.Id =
8, .Genero = "Hip Hop",
.Interprete = "Linkin Park",
.Titulo = "Meteora", .Precio =
60})
Dim
lobjDiscosSeleccionados = From
lobjSeleccionDiscos In lobjDiscos _
Where lobjSeleccionDiscos.Precio > 300 _
Order
By lobjSeleccionDiscos.Titulo Ascending _
Select
lobjSeleccionDiscos.Titulo, lobjSeleccionDiscos.Precio
For Each lobjDisc In
lobjDiscosSeleccionados
MessageBox.Show(lobjDisc.Titulo.ToString() + "
- " + lobjDisc.Precio.ToString())
Next
Asimismo también tenemos LINQ to dataSet que como ustedes se pueden imaginar nos permite
ejecutar queries is a través de las estructuras DataSet the que
ofrece. Net. Con esto podemos eliminar
desde luego el uso del objeto DataView que se montaba sobre un dataSet y que
nos permitía realizar funcionalidades equivalentes a un motor de base de datos
como el ordenamiento o el filtrado de los datos de acuerdo a sentencias
específicas ahora podemos utilizar LINQ directamente para extraer la
información deseada.
También tenemos LINQ
to XML donde es posible generar un query a partir de la declaración de un árbol
XML, LINQ to SQL que nos permite
(pronto un artículo sobre esto) generar objetos basándonos en la definición de
una base de datos relacional (un ORM con esteroides) y LINQ to Entities, una
tecnología que estará disponible en el futuro cercano cuyo objetivo es poner
una capa intermedia de a basada en XML donde se defina la estructura y mapeo de
los datos además de que contará con soporte a múltiples proveedores de base de
datos
6) Expresiones
lambda y conceptos sobre la programación funcional
El lenguaje de programación C# se está convirtiendo en un
lenguaje de programación funcional.
La programación funcional es un paradigma de la misma manera
que lo es el paradigma orientado objetos o la programación imperativa.
Existen lenguajes con enfoque el paradigma funcional desde
hace ya bastante rato, el ejemplo principal es Haskell.
Así como en la programación orientada a objetos se tiene
como objetivo primero describirle el mundo a la computadora mediante las clases
y luego resolver el algoritmo mediante la interacción (relaciones) entre los
objetos, el objetivo de la programación funcional es establecer “relaciones de
igualdad” (de la misma manera que sucede en las ecuaciones matemáticas).
En la programación funcional debemos pensar que todo es
una función y que el problema se resolverá mediante la generación de funciones
y su descomposición en otras funciones más simples, o bien al revés, que
podemos encontrar la solución a un problema componiendo funciones de funciones y evaluando expresiones que resultan de la
invocación de las mismas funciones. ¿Suena enredado? Para nada, es más fácil de
lo que se puedan imaginar.
Por ejemplo, sabemos que el doble de un numero x será x+x.
Utilizando la sintaxis de C# tenemos .
(En el siguiente ejemplo usamos expresiones lambda, para más
detalle ver este artículo)
C#
Doble x = (int
y) => y + y;
MessageBox.Show(x(2).ToString());
El resultado será 4
Así mismo sabemos que el cuádruple del mismo número será
el doble del doble, en lugar de generar otro método para definirlo, podemos
hacer uso de la inferencia de tipos que es básica en cualquier lenguaje de
programación funcional y escribir lo siguiente (y que desde luego C# y VB la
implementan)
var Cuadruple = x(x(2));
// o bien
var Cuadruple = x(2) + x(2) ;
MessageBox.Show(Cuadruple.ToString());
El resultado será 8
Y desde luego, si queremos saber el óctuple…
var Octuple = Cuadruple+Cuadruple;
MessageBox.Show(Octuple.ToString());
El resultado será 16.
Como podemos ver ya no estamos escribiendo más definiciones
de funciones ni creando su cuerpo, simplemente estamos haciendo referencia
mediante inferencia de tipos a una función que creamos al principio, como
podemos ver esto se traduce en un aumento de la productividad del programador porque
a resumidas cuentas nos estamos ahorrando una gran cantidad de código.
El soporte que tiene C#
para expresiones lambda (la base de la programación funcional) es mucho
mejor que el que existe en VB (por
ejemplo, en VB las expresiones lambda deben ser expresiones que generen valores
y no pueden ser sentencias, es decir no podemos crear una variable local dentro
del cuerpo de una expresión lambda, cosa que sí se puede con C#) y con el
futuro seguramente este soporte será ampliado.
Por su parte el equipo de VB ha decidido unir el destino del
veterano VB al destino de la programación en xml con características como XML
Literals (ver más abajo para más detalle).
Muchos programadores en C# quizá se sientan algo desilusionados debido a que el soporte en xml ahora es muchísimo más exhaustivo
en visual basic que en C#, sin embargo creo que la decisión del equipo de C#
tiene mucha lógica y se fundamenta en que las tecnologías alrededor de los
lenguajes son efímeras. No sabemos que pueda suceder en el futuro con el XML,
sobre todo cuando vienen nuevos como Astoria o Jasper (esperen un artículo de
esto en enero). ¿Seguirá siendo válido el XML en 2 años? ¿En 5? ¿En 15?. Eso
nadie lo sabe así que en C# se prefiere una filosofía más orientada al lenguaje
puro alejándolo de las cosas alrededor.
7) Literales
XML (Sólo VB)
Como les estaba comentando hace unas líneas el soporte a XML
que integra visual basic es mucho mayor al que integra C#. Sin ir más lejos o
simplemente examinen este código, no hay mucho que explicar
VB
Dim
lobjXML = <Peliculas>
<Pelicula>
<Titulo>El Exorcista</Titulo>
<Director>Juanito Perez</Director>
<Genero>Horror</Genero>
</Pelicula>
<Pelicula>
<Titulo>Saw 2 El juego del
miedo</Titulo>
<Director>Juanito Perez</Director>
<Genero>Terror</Genero>
</Pelicula>
<Pelicula>
<Titulo>Silent Hill</Titulo>
<Director>XXX Perez</Director>
<Genero>Suspenso</Genero>
</Pelicula>
</Peliculas>
MessageBox.Show(lobjXML.Elements.Count().ToString)
For
Each lobjElemento As
XElement In lobjXML.Elements
MsgBox(lobjElemento.Value())
Next
Como ustedes pueden ver automáticamente el compilador
reconoce cualquier declaración en xml
Y a partir de ella genera los objetos correspondientes para
que no podamos programar programa ticamente sin necesidad de utilizar clases
como XMLDocument. El código anterior nos muestra una bonita caja de texto con
los valores que se encuentran dentro del fragmento xml. Esto la verdad es
sorprendente, y se le denomina Literal Expression, ¡El XML ES el lenguaje de
programación, es parte íntegra de VB!
Inclusive si no queremos utilizar el For Each podemos
escribir un query y seleccionar aquellas películas que nos gusten mua ja ja…
VB
Dim
SeleccionXML = From Elemento In lobjXML.<Pelicula> _
Where Elemento.<Titulo>.Value = "Silent
Hill" _
Select Elemento.<Genero>
MsgBox(SeleccionXML.First.Value)
Este código nos
mostrará la palabra Suspenso. Y si queremos es todavía más allá es posible
generar XML que tenía como contenido en lugar de valores estáticos variables o
propiedades de objetos, sintaxis que seguramente les parecerá familiar
Dim
lobjXMLHoras = <Horas>
<Hora><Pais>México</Pais><HoraExacta><%= Now %></HoraExacta></Hora>
<Hora><Pais>Japón</Pais><HoraExacta><%= Now.AddHours(6) %></HoraExacta></Hora>
</Horas>
Del ejemplo anterior hemos puesto como valores el elemento
HoraExacta al cálculo de la hora actual y en el caso del segundo elemento
estamos añadiendo unas horas para representar un cálculo.
Algo que no puedo dejar de mencionar y que es medio horrible
es que no es posible de debuggear las expresiones cuery en la ventana de immed.
Esperemos que en próximas revisiones nuestros compas en Microsoft le den un vistazo esto porque se puede volver
un feo dolor de cabeza a la hora de programar cueris complejos. (Si pudieron
con las nested master pages, que no puedan con esto juar juar)
“Query expressions are
not valid in debug windows”
8) Operador
ternario(Sólo VB)
Por todos es conocido que es posible representar un If en C#
de la siguiente manera
C#
a%b==0 ? "Par" : "Non";
A pesar de que las versiones anteriores de visual basic o
tenían una función llamada Iif, esta sintaxis era exactamente eso: una función
por lo cual si alguno de las expresiones que se le pasaban esta función era
inválida tronaba toda nuestra rutina. Como buena noticia ya ningun programador
en C# se podrá burlar de los visualeros. Les presento al poderosísimo operador
ternario en VB:
VB
If(lintNumero Mod 2 = 0, "Par", "Non")
9) Propiedades
autoimplementadas (Sólo C#)
Sabemos nosotros que cuando estamos utilizando propiedades
siempre es indispensable utilizar una variable privada dentro de la clase que
se encargue de mantener el Valor que está expuesto por la propiedad en la
versión 2005 de visual studio se introdujo el concepto de Refactoring que
mediante el IDE nos permitía generar automáticamente estas variables, ahora
esto se llevado a nivel de lenguaje y es posible generar implícitamente la
variable privada que contendrá el tipo utilizando la siguiente sintaxis.
C#
public string Disquera {get;
set;}
Bien, ahora sí, a esperar el año nuevo y fuera de coto, mis
mejores deseos para el 2008, gracias por seguir entrando a DevelopersDotNet y
les aseguro que en el 2008 este blog tratará, como lo ha intentado desde su
creación de poner cosas, aunque sea medianamente originales y que aporten valor
a este horrible pero genial armatoste llamado Internet.
Un abrazo a tod@s y
¡Feliz codificación!