ESCRIBIENDO "HOLA MUNDO" EN C# 3.0 (Visual Studio Express 2008)

 

"Hola Mundo" es el clásico primer programa cuando se aprende un lenguaje de programación. Por ejemplo, para escribir "Hola Mundo" en C# basta poner:

Lo único que se tiene que añadir son las dos líneas Console... Lo demás nos lo pone el Visual Studio.

La idea aquí es escribir "Hola Mundo" de la manera más difícil y obtusa que se me pueda ocurrir. Combinado todas las rarezas de las que tengo conocimiento (punteros, expresiones lambda y recursividad) llegué a esto:

class Program

{

delegate void Hm(int k);

static void Main(string[] args)

{

char[] m = new char[10];

m[0] = 'H'; m[5] = 'M';

m[1] = 'o'; m[6] = 'u';

m[2] = 'l'; m[7] = 'n';

m[3] = 'a'; m[8] = 'd';

m[4] = ' '; m[9] = 'o';

unsafe { fixed (char* p = m) { Hm H = (k) => recurd(k, p); H(0); } }

Console.ReadLine();

}

static unsafe int recurd(int i, char* p)

{

Console.Write(p[i]);

return i == 10 ? 0 : recurd(i + 1, p);

}

}

Lo que primero hice fue declarar un vector o array tipo char donde se guardaría cada caracter de "Hola Mundo" incluyendo el espacio en blanco. C# admite el uso de punteros en un "contexto no seguro", es decir, en aquellos pedazos del código declarados como "unsafe". Si el puntero además de declara como "fixed" significa que no se puede incrementar, está "fijado" y la dirección de memoria a la que apunta no puede cambiar.

En Visual Studio, además hay que ir a Proyecto->Propiedades y en Generar, activar la casilla de "Permitir Código no Seguro":

Cuando se opera con punteros, por experiencia digo que lo mejor es usarlos para apuntar a sectores de la memoria ya asignados a nuestra aplicación (en caso del C++ suelo declarar los arrays de forma estática y hacer que los punteros apunten allí), esto es para evitar los problemas de los punteros cuando por error terminan apuntando a sitios en la memoria que no debían y hacen que nuestra aplicación se cuelgue. Por ello primero declaro el array, le asigno valores, y luego uso un puntero para recorrerlo (teniendo cuidado siempre en no sobrepasar el tamaño del array).

Una vez declarado el array con el "Hola Mundo" llamo a una función recursiva desde una función lambda. El recorrido del array, así como su escritura en pantalla, se realizan en la función "recurd". Dado que la función recursiva devuelve un dato tipo "int", el parámetro de la función lambda también es "int".

La función recursiva recibe dos parámetros: el "int" y el puntero que apunta a un dato tipo char. Es el dato "int" el que se incrementa y el que da la condición para parar a la función recursiva, dado que el puntero no es "condición de parada" no interesa su valor. 

return i == 10 ? 0 : recurd(i + 1, p);  equivale a poner: if (i==10) return 0; else return recurd(i + 1, p); La expresión adquiere o devuelve el valor correspondiente según el resultado. Por ejemplo, el siguiente código escribirá la letra "a" (el valor adquirido por la variable k):

 

En sí mi programita para escribir "Hola Mundo" no estaba mal, pero el código dentro de la función "recurd" podía ir dentro de la expresión lambda. Haciendo este cambio el código me quedó así, bastante más compacto:

class Program

{

delegate int Hm(Hm h, int k);

static void Main(string[] args)

{

char[] m = new char[10];

m[0] = 'H'; m[5] = 'M';

m[1] = 'o'; m[6] = 'u';

m[2] = 'l'; m[7] = 'n';

m[3] = 'a'; m[8] = 'd';

m[4] = ' '; m[9] = 'o';

unsafe { fixed (char* p = m) {

Hm H = (h, k) => { Console.Write(p[k]); return k == 10 ? 0 : h(h, k+1); };

H(H,0); //int r = H(H,0);

}

}

Console.ReadLine();

}

}

Lo que hice simplemente fue ponerle a la función lambda la forma de la función "recurd". La función lambda devuelve un dato tipo int que puede asignarse a una variable si se desea.

Acomodando un poco, finalmente queda así:

class Program

{

delegate int Hm(Hm h, int k);

unsafe static void Main(string[] args)

{

char[] m = new char[10];

m[0] = 'H'; m[5] = 'M';

m[1] = 'o'; m[6] = 'u';

m[2] = 'l'; m[7] = 'n';

m[3] = 'a'; m[8] = 'd';

m[4] = ' '; m[9] = 'o';

fixed (char* p = m) { Hm H = (h, k) => { Console.Write(p[k]); return k == 10 ? 0 : h(h, k+1); }; H(H,0); }

Console.ReadLine();

}

}