Solving Combinatory Problems with LINQ

Originally published by MSDN in April, 2010.

The other day I ran into a very interesting blog post by Intel engineer James Cownie, Intel Parallel Studio: Great for Serial Code Too (Episode 1). The article uses as an example an application that solves the following problem (I quote):

Find a number consisting of 9 digits in which each of the digits from 1 to 9 appears only once. This number must also satisfy these divisibility requirements:

  1. The number should be divisible by 9.
  2. If the rightmost digit is removed, the remaining number should be divisible by 8.
  3. If the rightmost digit of the new number is removed, the remaining number should be divisible by 7.
  4. And so on, until there’s only one digit (which will necessarily be divisible by 1).

While the C++ solution proposed by the author in that article runs along more “conventional” lines, I (having the enormous luck of being a C# developer) was immediately drawn to applying LINQ to tackle this problem. I find LINQ an ideal tool for solving this type of exploratory problem, where one needs to traverse a full tree of possible combinations, backtracking from unsuccessful branches as soon as they are encountered.

With LINQ queries, cascaded from clauses serve as the generators of combinations, while where clauses determine the failure points that trigger backtracking. The first time I saw this technique used was in the blog post Using LINQ to solve puzzles, by Luke Hoban, a member of the Microsoft Languages Team. I was inspired to write about the approach in my book C# 3.0 and LINQ (C# 3.0 y LINQ, Krasis Press, 2007 (in Spanish)), and then occasionally in my blog, the last time to solve a puzzle involving the generation of a magic square similar to the Dührer square mentioned in the latest Dan Brown bestseller, The Lost Symbol. The post, Buscando el símbolo perdido con LINQ, is in Spanish.

The code that follows shows my implementation of the solution to the problem, which I find a good example of the enormous expressive power of LINQ.

using System;
using System.Linq;
 
namespace Geeks
{
  // C# and LINQ solution to the numeric problem presented in: 
  // http://software.intel.com/en-us/blogs/2009/12/07/intel-parallel-studio-great-for-serial-code-too-episode-1/
  class MainClass
  {
    static void Main()
    {
      int[] oneToNine = new int[] { 123456789 };

      // the query 
      var query =
        from i1 in oneToNine
        from i2 in oneToNine
        where i2 != i1
           && (i1 * 10 + i2) % 2 == 0
        from i3 in oneToNine
        where i3 != i2 && i3 != i1
           && (i1 * 100 + i2 * 10 + i3) % 3 == 0
        from i4 in oneToNine
        where i4 != i3 && i4 != i2 && i4 != i1
           && (i1 * 1000 + i2 * 100 + i3 * 10 + i4) % 4 == 0
        from i5 in oneToNine
        where i5 != i4 && i5 != i3 && i5 != i2 && i5 != i1
           && (i1 * 10000 + i2 * 1000 + i3 * 100 + i4 * 10 + i5) % 5 == 0
        from i6 in oneToNine
        where i6 != i5 && i6 != i4 && i6 != i3 && i6 != i2 && i6 != i1
          && (i1 * 100000 + i2 * 10000 + i3 * 1000 + i4 * 100 + i5 * 10 + i6) % 6 == 0
        from i7 in oneToNine
        where i7 != i6 && i7 != i5 && i7 != i4 && i7 != i3 && i7 != i2 && i7 != i1
          && (i1 * 1000000 + i2 * 100000 + i3 * 10000 + i4 * 1000 + i5 * 100 + i6 * 10 + i7) % 7 == 0
        from i8 in oneToNine
        where i8 != i7 && i8 != i6 && i8 != i5 && i8 != i4 && i8 != i3 && i8 != i2 && i8 != i1
          && (i1 * 10000000 + i2 * 1000000 + i3 * 100000 + i4 * 10000 +
              i5 * 1000 + i6 * 100 + i7 * 10 + i8) % 8 == 0
        from i9 in oneToNine
        where i9 != i8 && i9 != i7 && i9 != i6 && i9 != i5 && i9 != i4 && i9 != i3 && i9 != i2 && i9 != i1
        let number = i1 * 100000000 +
                     i2 * 10000000 +
                     i3 * 1000000 +
                     i4 * 100000 +
                     i5 * 10000 +
                     i6 * 1000 +
                     i7 * 100 +
                     i8 * 10 +
                     i9 * 1
        where number % 9 == 0
        select number;

      // run it! 
      foreach (int n in query)
        Console.WriteLine(n);
    }
  }
}

Note that no attempt at all has been made to optimize the code (for instance, applying individual divisibility criteria for the different positions). I firmly believe in Don Knuth‘s statement that “premature optimization is the root of all evil,” and the program as it stands perfectly satisfied my expectations. On my laptop, it finds the only solution to the problem (the number 381654729) in much less than a second.

Descartes en C# 7

“Don’t discard me / Just because you think I mean you harm …”
Elton John, “Don’t let the sun go down on me” (1974)

Entre las nuevas características de lenguaje incorporadas a C# 7, una relativamente sencilla que ha llamado mi atención son los descartes (discards). Según dice Matt Torgersen en las notas sobre el diseño de C#, el cambio del término que estaba previsto, wildcards, por discards (para mí tremendamente acertado), fue propuesto al equipo de C# durante el último MVP Summit celebrado en Seattle.

Creo que descarte es el término castellano que debiéramos utilizar, vistas sus acepciones en el diccionario de la Real Academia Española: “1) Acción de descartar o descartarse. 2) En varios juegos de naipes, cartas que se desechan o quedan sin repartir”. Y espero sinceramente que dentro de una o dos décadas, cuando se enseñe a programar desde la más tierna infancia, se añada al diccionario un nuevo significado para esta palabra: “En ciertos lenguajes de programación, nombre que se da a variables locales de solo escritura generadas por el compilador”.

Básicamente, los descartes nos ahorran la necesidad de asignarle explícitamente un nombre a una variable que no vamos a utilizar después de su primera aparición en el código fuente (en la que se le asigna un valor). Me recuerdan a una característica muy parecida que ofreció desde sus inicios el lenguaje de programación lógica Prolog (donde también se utiliza un simple subrayado para denotar a los descartes), aunque allí la cosa va de unificación bidireccional, y no de la simple asignación.

El ejemplo más típico de uso de los descartes es probablemente el relacionado con el parámetro out que ofrecen las diferentes implementaciones de TryParse() diseminadas a lo largo de las librerías de .NET Framework. Si nuestro único interés es validar la cadena de caracteres de entrada, entonces no es necesario que nos preocupemos por dar nombre a la variable que recibirá el valor interpretado correspondiente. El pequeño programa a continuación muestra, de hecho, dos posibles maneras de hacer más concisa la notación al trabajar con parámetros de salida en la última versión de C#:

namespace Geeks
{    
    class TestBed
    {
        static void Main(string[] args)
        {
            string test = "32A";
 
            Console.WriteLine(IsValidInt6(test));
            Console.WriteLine(IsValidInt7A(test));
            Console.WriteLine(IsValidInt7B(test));
        }
 
        static bool IsValidInt6(string s)  // C# 6 y anteriores
        {
            int temp;
            return int.TryParse(s, out temp);
        }
        static bool IsValidInt7A(string s)  // C# 7 
        {
            return int.TryParse(s, out int temp);
        }
        static bool IsValidInt7B(string s)  // C# 7
        {
            return int.TryParse(s, out _);
        }
    }
}

Otros contextos en los que los descartes pueden ser de utilidad tienen relación con otras novedades de C# 7: las nuevas posibilidades de la sentencia switch y el emparejamiento de patrones (pattern matching). Pero esos son temas para próximas entradas, así que lo dejaremos aquí por ahora; no sin antes mencionar que a partir de C# 7 el lexema _ es una nueva palabra reservada contextual, y que su utilización en contextos en los que se encuentre definida una variable local con ese mismo nombre puede provocar problemas como los que se describen aquí.


Referencia musical: ¿Qué decir sobre Elton John que no se haya escrito ya? Un genio como pocos ha habido, durante la década de los ’70 publicó (siempre con la inestimable colaboración de su letrista, Bernie Taupin) discos que hoy son clásicos del pop/rock a razón de dos por año, hasta que llegó a los diez que necesitaba para cumplir su contrato con MCA e independizarse. Y aunque, en general, los discos que siguieron no han estado a la altura de aquellos otros (¿puede la libertad ser contraproducente, amigo lector?), Elton ha conseguido mantener su popularidad hasta el presente. El tema “Don’t let the sun go down on me” apareció originalmente en el disco “Caribou” (1974); pero solo llegó al número 1 de las listas en 1991, gracias a una versión a dúo con el ya fallecido George Michael.

Abriendo una caja fuerte

“They got the money, hey / You know they got away
They headed down south and they’re still running today …”
The Steve Miller Band, “Take the Money and Run” (1976)

Como la entrada anterior trataba sobre recursividad, la técnica “divide y vencerás” y las funciones internas de C# 7, aprovecho para mostrar una solución a un problema que le plantearon a un antiguo colega que se presentó a una entrevista de trabajo en Google (debe haberle ido bien, porque lo aceptaron). El enunciado del problema es el siguiente:

Una caja fuerte está protegida mediante una combinación de cuatro dígitos decimales. La caja fuerte solo tiene en cuenta los cuatro últimos dígitos tecleados a la hora de decidir si los datos tecleados satisfacen la contraseña. Por ejemplo, si alguien teclea en la caja fuerte los dígitos 012345, con ello habrá probado las combinaciones 0123, 1234 y 2345. Obviamente, la secuencia de 40000 dígitos 0000000100020003…9999 abrirá con total seguridad la caja fuerte. Ahora bien, ¿podrían cubrirse todas las 10000 posibles combinaciones utilizando una secuencia de menor longitud? ¿Cuál es la longitud de la cadena más corta que permite probar todas las combinaciones?

Desde que mi ex-colega me lo describió, me pareció que el problema se prestaba para ser atacado mediante una función recursiva con la que se va avanzando o retrocediendo (backtracking) en el espacio de combinaciones del problema. Y como al que tiene un martillo todos los problemas se le parecen a un clavo, me puse inmediatamente a teclear y al cabo de una media hora le tenía preparado algo muy parecido al código siguiente:

using System;
using System.Linq;
 
namespace Geeks.SafeCrack
{
    static class MainClass
    {
        static void Main(string[] args)
        {
            GoForward(SafeData.InitialData);
        }

        static bool GoForward(SafeData safeData)
        {
            if (safeData.IsCracked)
            {
                PrintResults();
                return true;
            }

            var len = safeData.Sequence.Length;
            var a = (int) safeData.Sequence[len - 3] - '0';
            var b = (int) safeData.Sequence[len - 2] - '0';
            var c = (int) safeData.Sequence[len - 1] - '0';

            for (int d = 0; d <= 9; d++)
            {
                var index = SafeData.Index(a, b, c, d);
                if (safeData.Combinations[index])
                    continue;
                
                var newSequence = safeData.Sequence + (char)('0' + d);
                var newCombinations = (bool[]) safeData.Combinations.Clone();
                newCombinations[index] = true;
                if (GoForward(new SafeData(newSequence, newCombinations)))
                    return true;
            }
            return false;
 
            void PrintResults()
            {
                Console.WriteLine("Safe cracked!!!");
                var sequence = safeData.Sequence;
                Console.WriteLine("Length   = " + sequence.Length);
                Console.WriteLine("Sequence = " + sequence);
            }
        }
    }
 
    class SafeData
    {
        public SafeData(string sequence, bool[] combinations)
        {
            Sequence = sequence;
            Combinations = combinations;
        }
        public string Sequence { getprivate set; }
        public bool[] Combinations { getprivate set; }

        public bool IsCracked => Combinations.All(x => x);

        private readonly static SafeData initialData = 
            new SafeData("000"new bool[10000]);
        public static SafeData InitialData => initialData;

        public static int Index(int a, int b, int c, int d) =>
            1000 * a + 100 * b + 10 * c + d;
    }
}

Básicamente, en cada paso del algoritmo se examina con cuáles de los diez dígitos se puede extender la secuencia actual, añadiendo una nueva combinación a la lista de combinaciones ya probadas, y para cada uno de tales dígitos se avanza en profundidad. Una vez analizados los diez dígitos, se hace backtrack al contexto de la llamada inmediatamente anterior (que continuará recorriendo sus dígitos aún pendientes).

La longitud de cadena que produce el programa anterior es 10003, y dado que el programa está diseñado para retroceder masivamente una vez que se encuentra la primera solución, todo indica que navegué con mucha suerte, ya que ésta resulta ser precisamente la longitud óptima. El programa puede ser modificado fácilmente para explorar todo el espacio de combinaciones y enumerar todas las soluciones existentes, tarea que dejo al lector interesado. Pero la moraleja de esta historia no radica tanto en la utilización de la recursividad y el backtracking como en la importancia de la preparación teórica (en general) y la investigación sobre el problema (en particular) antes de ponerse a codificar como un poseso: como puede comprobarse aquí y en muchas otras fuentes, reconociendo la aplicabilidad del concepto de secuencia de De Bruijn no habría hecho falta tirar ni una sola línea de código para saber que la respuesta correcta es 10003.


Referencia musical: Uno de mis grupos favoritos de la segunda mitad de la década de los ’70 fue la banda de Steve Miller, músico recientemente incorporado al Salón de la Fama del Rock’n’Roll que desarrolló prácticamente toda su carrera en San Francisco. El tema “Take the Money and Run” fue el primer single de uno de sus discos más exitosos, “Fly Like an Eagle” (1976). Pero es probablemente el tercer éxito, el que le da el nombre al disco, el que más perdura en la memoria hoy en día; la crítica social de su letra siempre me recuerda que California (y especialmente el norte) es desde hace muchísimo tiempo una región netamente “progre”.

Funciones locales en C# 7

“And if my shadow is all that survives
I’m still alive …”
Meat Loaf, “Alive” (2006)

Aprovecho la suerte de que este blog sigue aún activo (¡muchas gracias por ello a mis buenos amigos de Plain Concepts!) para dar señales de vida después de hace bastante tiempo.

Revisando varios recursos online relacionados con las novedades incorporadas a C# 7 (incluyendo una excelente entrega de la serie Plain TV, que sigo regularmente), me pareció sumamente curioso que prácticamente ninguno de los vídeos consultados utilizaran, al presentar las funciones locales (local functions, véase descripción en MSDN), lo que para mí es el ejemplo por excelencia de uso de las mismas. Después de darle vueltas al tema por un buen rato, he llegado a la conclusión de que probablemente todo es consecuencia de varias décadas de enseñanza de la programación utilizando lenguajes que no ofrecen (u ofrecían) la posibilidad de anidar funciones (léase Java, C++ y el propio C#). Allá por los años 80, la Universidad de La Habana y muchos otros centros docentes utilizaban como vehículo de iniciación el lenguaje Pascal, que siempre ofreció esa posibilidad; no creo que ninguno de mis antiguos alumnos se haya “escapado” de haber visto algún ejemplo de utilización de esta característica para acotar el ámbito (visibilidad) de un  procedimiento/función.

El patrón de utilización de funciones anidadas al que me refiero se presenta comúnmente al programar algoritmos basados en la estrategia “divide y vencerás”, y lo ejemplificaré aquí a través de una implementación del método QuickSort1 para ordenar un array de enteros en su sitio (in place). Al aplicar esta estrategia, aparecen funciones auxiliares cuyo ámbito natural es la rutina como parte de la cual han sido concebidos; muy frecuentemente estas funciones son recursivas. En el caso de QuickSort, cuya implementación muestro más abajo, esta posibilidad de anidamiento se presenta a varios niveles:

  • Al nivel más externo, la necesidad de ofrecer una implementación “limpia” nos exige exponer un método que solo requiera como parámetro el array a ordenar. Pero la naturaleza misma del algoritmo, como se describe a continuación, nos exige disponer de otra versión que reciba los índices inferior y superior sobre los que se va a actuar en el marco de una llamada cualquiera. Una función anidada es la solución ideal, dado que esta última versión no necesita ser expuesta al exterior (ni  siquiera otros métodos de la clase).
  • La idea central del algoritmo consiste en colocar de manera económica uno de los valores en el array en su posición final, con todos los valores menores que él a su izquierda y los mayores a su derecha (un proceso que se conoce como partición), para luego aplicar recursivamente la ordenación a los dos sub-arrays situados, respectivamente, a la izquierda y la derecha de ese elemento pivote. En nuestra implementación, la versión “interna” de QuickSort hace a su vez uso de una función local a ella, Partition, para hacer la partición del fragmento de array recibido.
  • Esta idea de descomposición funcional “hacia adentro” podría extenderse tanto como fuera necesario; a riesgo de lucir pedante, en el ejemplo he creado dentro de Partition una función Swap para intercambiar los valores de dos elementos del array, dados sus índices.

Observe el lector que el uso de funciones locales no solo produce un encapsulamiento más correcto del código, sino que además permite capturar en la función anidada los parámetros y variables locales de la función que la contiene, lo que se traduce tanto en economía de expresión como en mejoras en el rendimiento.

namespace Geeks
{
   public static class Utilities
   {
      public static void QuickSort(this int[] a)
      {
         void QuickSort(int first, int last)
         {
            int Partition()
            {
               void Swap(int p, int q)
               {
                  int tmp = a[p];
                  a[p] = a[q];
                  a[q] = tmp;
               }
 
               int pivot = a[first], index = first;
               Swap(index, last);
               for (int i = first; i < last; i++) 
                  if (a[i] < pivot) Swap(index++, i);
               Swap(index, last);
               return index;
            }

            if (first < last)
            {
               int pivotIndex = Partition();
               QuickSort(first, pivotIndex - 1);
               QuickSort(pivotIndex + 1, last);
            }
         }

         QuickSort(0, a.Length - 1);
      }
   }

   class Program
   {
      static void Main(string[] args)
      {
         var x = new int[] { 75824 };
         x.QuickSort();
      }
   }
}

1 Una descripción independiente del lenguaje de QuickSort puede verse aquí, y su implementación utilizando anidamiento aquí.


Referencia musical: Por allá por la segunda mitad de la década de los 70, cuando aún era un adolescente, un artista con el estrambótico nombre de Meat Loaf llamó poderosamente mi atención gracias a un peculiar estilo operístico, que combinaba el pop/rock tradicional con elementos de rock sinfónico. Con el tiempo, el disco “Bat Out of Hell” (1977) ha llegado a convertirse en uno de los diez más vendidos de todos los tiempos, y ha dado lugar a dos secuelas (también bastante exitosas) en 1993 y 2006. El tema “Alive” pertenece al tercer disco de la trilogía.

Acerca de “Solving Combinatory Problems with LINQ”

“I saw you, I knew you, I touched you
When the world was young …”
Jimmy Page & Robert Plant, “When the World Was Young” (1998)

Hace unos días, en el contexto de una conversación con un colega de trabajo, me acordé del artículo “Solving Combinatory Problems with LINQ“, que en su día me publicó gentilmente MSDN y aún sigue por ahí (también lo he copiado aquí, con el código listo para copiar y pegar). Sin duda alguna, y por una diferencia abismal (gracias, por supuesto, a Microsoft), es el texto más leído que haya escrito yo jamás, y en su momento dio lugar a discusiones como ésta.

Revisando el artículo al cabo de todo este tiempo, se me antoja ciertamente un poco naïve; me consuela la idea de que, al fin y cabo, eran tiempos en que “el mundo era joven” y LINQ acababa de nacer.


Referencia musical: Durante la década de los 90, los líderes del inolvidable Led Zeppelin, Jimmy Page y Robert Plant, publicaron dos discos que hicieron las delicias de los numerosos fans de la banda: “No Quarter” (1994) y “Walking into Clarksdale” (1998). “When the World Was Young” pertenece al segundo de esos trabajos.

"Welcome to the Jungle" en dNM

”Welcome to the jungle / We’ve got fun ‘n games 
We’ve got everything you want / Honey, we know the names…”
Guns N’ Roses, “Welcome to the Jungle” (1987)

Una de las personalidades del mundo de la informática cuya trayectoria sigo desde hace años con más interés (y admiración) es Herb Sutter, Lead Architect del equipo de Visual C++ en Microsoft y Chair del Comité de Estandarización de C++. Se trata, sin dudas, de una luminaria, cuya relevancia transciende las fronteras de la empresa para que trabaja y cuyos múltiples aportes permean a toda la industria informática. Herb es, además, un consumado comunicador, que destaca tanto por sus conferencias (de entre las más recientes, ver, por ejemplo, las dedicadas a C++ 11 en los eventos “Going Native 2012” y “Lang.NEXT 2012”, disponibles en Channel 9), sus libros (“Exceptional C++” y “More exceptional C++” son realmente excepcionales), como por sus artículos. De entre estos últimos, quisiera destacar dos que han constituido, cada uno en su momento, certeros análisis de la situación actual del hardware y de las implicaciones de dicha situación para el desarrollo de software: “The Free Lunch is Over” (diciembre de 2004) y “Welcome to the Jungle” (diciembre de 2011), este último disponible públicamente en su sitio web.

Durante el pasado mes de febrero, Herb tuvo la gentileza de conceder una entrevista a dNM (antes dotNetManía), en la que cuenta a Luis Fraile los detalles de sus actividades al frente de los equipos de trabajo dedicados al desarrollo de WinRT y Visual C++ en Microsoft, así como del Comité de Estandarización de C++. Pero no solo eso: Herb tuvo asimismo la amabilidad de permitirnos traducir “Bienvenido a la jungla (del hardware)” y publicarlo en castellano, para de esta forma hacerlo llegar a un público aún más amplio. Así que si aún no ha leído el artículo y desea conocer (en nuestro idioma) las opiniones de Herb Sutter con respecto al presente y futuro de la informática, y en particular sobre temas de tanta actualidad como el estado actual de la Ley de Moore o el futuro de la nube, no se pierda los ejemplares de abril y mayo de este año (nº 91 y 92) de dNM.


Referencia musical: Me imagino que Herb se haya “inspirado” para dar título al artículo en el famoso tema homónimo de Guns N’ Roses; banda que ocupó uno de los lugares más destacados en el rock de finales de los ’80 y principios de los ’90, y que dejó una huella que perdura hasta el presente. Incluso he visto algunas encuestas recientes que sitúan a Axl Rose como el frontman más destacado de todos los tiempos, un lugar que para mí siempre ocupará Robert Plant. Personalmente, el esplendor de Guns N’ Roses coincidió con una época en la que no oía mucho rock; tiempos duros, como son casi siempre los que preceden y suceden a una emigración.

NOTA: Las opiniones reflejadas en este artículo son mías propias, y no han sido revisadas ni aprobadas por la empresa en la que trabajo.

Applying LINQ to new data types

[This article was originally published in MSDN C# Developer Center, February 2008]

Given the enormous expressive power that LINQ (Language Integrated Query) puts in the hands of developers, it is not surprising that we have started to search for ways to “LINQ-enable” more and more data types and technologies. As Dinesh Kulkarni humorously put it in this post, soon we will have even “LINQ to Coffee Machine” :-). .NET Framework 3.5 and C# 3.0 offer us several ways to achieve that goal.

In many occasions, all that is needed in order to be able to apply integrated queries to objects of a certain type (of our own, or belonging to the .NET Framework class library) is to define for the type one or more entry points which could serve as the generators to which all the basic object query machinery incorporated into .NET Framework (LINQ to Objects) can be applied. This has been, for instance, the approach used in LINQ to XML, where a set of iterators (implemented as extension methods) have been defined that produce subsets of the nodes that compose an XML document as IEnumerable<T> sequences; once you call any one of these methods, you obtain an XML node generator to which the predefined implementations of the standard query operators Where(), OrderBy(), etc. can be applied. LINQ to XML also introduces several specialized query operators (“extensions”), but that’s another story.

As an example of simple “LINQ activation” of classes, here we present the implementation of an extension that will allow us to use integrated query syntax over data received through a named pipe. Pipes are a well-known inter-process communication mechanism that has been in use since very long in the DOS/Windows world; but only with .NET Framework 3.5 we will be able to use them in our managed code applications without having to recur to platform invocation. Pipes can be anonymous, conceived to be used to communicate a parent process and a child process residing on the same machine; or named, which offer much more power and can be used over a network. Specifically, named pipes offer message-oriented communications.

The following program implements a server which sends UTF8-encoded string messages to its listener through a pipe named CS3:

using System;
using System.Text;
using System.IO;
using System.IO.Pipes;

namespace Demos
{
class Server
{
static void Main(string[] args)
{
const string PipeName = “CS3”;

using (NamedPipeServerStream pipeStream =
new NamedPipeServerStream(PipeName, PipeDirection.InOut,
1, PipeTransmissionMode.Message, PipeOptions.None))
{
pipeStream.WaitForConnection();

// sending messages
UTF8Encoding encoding = new UTF8Encoding();
for (int i = 1; i <= 1000; i++)
{
string msg = i.ToString();
byte[] bytes = encoding.GetBytes(msg);
pipeStream.Write(bytes, 0, bytes.Length);
}
}
}
}
}

The client, on the other end, composes received messages:

namespace Demos
{
class Client
{
static void Main(string[] args)
{
const string Server = “.”;
const string PipeName = “CS3”;

using (NamedPipeClientStream pipeStream =
new NamedPipeClientStream(Server, PipeName, PipeDirection.InOut))
{
pipeStream.Connect();
pipeStream.ReadMode = PipeTransmissionMode.Message;

Decoder decoder = Encoding.UTF8.GetDecoder();

const int BufferSize = 256;
byte[] bytes = new byte[BufferSize];
char[] chars = new char[BufferSize];
int numBytes = 0;
StringBuilder msg = new StringBuilder();
do
{
msg.Length = 0;
do
{
numBytes = pipeStream.Read(bytes, 0, BufferSize);
if (numBytes > 0)
{
int numChars = decoder.GetCharCount(bytes, 0, numBytes);
decoder.GetChars(bytes, 0, numBytes, chars, 0, false);
msg.Append(chars, 0, numChars);
}
} while (numBytes > 0 && !pipeStream.IsMessageComplete);
decoder.Reset();
if (numBytes > 0)
{
// we’ve got a message – process it
Console.WriteLine(msg.ToString());
}
} while (numBytes != 0);
}
Console.ReadLine();
}
}
}

What if the client process needed to filter, sort, group, etc. the received strings? Traditional coding approaches to implement these tasks could be applied, of course, but a more far-sighted approach would be to define a “LINQ entry point” in the form of an extension method for the NamedPipeClientStream class, so that it can be used as source for language integrated queries:

namespace PlainConcepts.Linq
{
public static partial class Extensions
{
public static IEnumerable<string> GetMessages(
this NamedPipeClientStream pipeStream)
{
pipeStream.Connect();
pipeStream.ReadMode = PipeTransmissionMode.Message;

Decoder decoder = Encoding.UTF8.GetDecoder();

const int BufferSize = 256;
byte[] bytes = new byte[BufferSize];
char[] chars = new char[BufferSize];
int numBytes = 0;
StringBuilder msg = new StringBuilder();
do
{
msg.Length = 0;
do
{
numBytes = pipeStream.Read(bytes, 0, BufferSize);
if (numBytes > 0)
{
int numChars = decoder.GetCharCount(bytes, 0, numBytes);
decoder.GetChars(bytes, 0, numBytes, chars, 0, false);
msg.Append(chars, 0, numChars);
}
} while (numBytes > 0 && !pipeStream.IsMessageComplete);
decoder.Reset();
if (numBytes > 0)
{
// we’ve got a message – yield it!
yield return msg.ToString();
}
} while (numBytes != 0);
}
}
}

Note that thanks to the use of an iterator, queries built around this extension method will take advantage of lazy evaluation, so that messages will be retrieved on demand, as they are needed by the client application.

With such an extension method at hand, we will be able to process messages received from a named pipe stream this way:

namespace Demos
{
using PlainConcepts.Linq;

class Client
{
static void Main(string[] args)
{
const string Server = “.”;
const string PipeName = “CS3”;

using (NamedPipeClientStream pipeStream =
new NamedPipeClientStream(Server, PipeName, PipeDirection.InOut))
{
var input = from s in pipeStream.GetMessages()
where string.Compare(s, “3”) < 0
orderby s
select s;
foreach (var s in input)
Console.WriteLine(s);
}
Console.ReadLine();
}
}
}

Processing messages this way can save us a lot of coding, making at the same time our code much more elegant and readable.

Download source code (VS 2010)

"C# 3.0 y LINQ" disponible en formato PDF

”All over the world
Everybody got the word …”
The Electric Light Orchestra, “All Over the World” (1980)

Desde hace unos días, todos los libros de la editorial Krasis Press (incluido mi “C# 3.0 y LINQ“) están a la venta en formato PDF a precios, en mi opinión, muy razonables. Como hacen prácticamente todas las demás casas que editan contenidos digitales, las copias personalizadas se generan dinámicamente y llevan una traza que identifica al comprador final.

Hace tiempo que perdí la cuenta de los amigos de toda Latinoamérica que me han escrito desde la publicación del libro, preguntando cómo conseguir un ejemplar; me consta que en una gran parte de los casos la ilusión se esfumaba completamente cuando la editorial, a quien yo trasladaba puntualmente los mensajes, les comunicaba los (inevitables) gastos de envío asociados a la compra. A partir de ahora, para decirlo en gallego (como una especie de homenaje a mi buen amigo José Manuel Alarcón :-), ¡Nunca mais!


Referencia musical: The Electric Light Orchestra (ELO) fue un grupo de pop-rock que gozó de gran popularidad durante los ´70 y buena parte de los ´80. Surgido con la idea de crear un rock con referencias a la música clásica (si le interesa, busque la versión de ELO de “Roll Over Beethoven“, que data de 1973), lo que me atrajo originalmente hacia ELO fue la presencia en la banda de mi instrumento favorito, el violín. Como ocurrió a muchos de los grupos de la época, su sonido se fue haciendo más comercial en la medida que el éxito iba creciendo; “All over the World” (1980) forma parte de la banda sonora de la película musical “Xanadú“.

Libros recomendados

”So you run and you run to catch up with the sun but it’s sinking
Racing around to come up behind you again…”
Pink Floyd, “Time”, from “The Dark Side of the Moon” (1973)

De manera similar a lo que sugiere el tema inmortal de Pink Floyd, esto de estar al día en todas las tecnologías que nos interesan se convierte cada vez más en misión imposible: cuando crees que ya “controlas” la versión N de la tecnología X, aparece su versión N+1.

Durante los últimos fines de semana, he estado intentando ponerme al día en algunas de las tecnologías que no utilizo de momento en el día a día y que han progresado bastante desde la última vez que “tropecé” seriamente con ellas; concretamente, me refiero a Silverlight y Entity Framework. Para ello, me he apoyado en dos excelentes recursos en castellano, escritos por grandes amigos y aún mejores profesionales, que se me antojan ideales no solo para los desarrolladores .NET castellanohablantes que quieran ponerse al día en las más recientes novedades incorporadas a las respectivas tecnologías, sino también para aquellos que se aproximen por primera vez a ellas y necesiten una fuente que los lleve de la mano, prácticamente desde cero y de una manera concisa, pero completa, a través de los múltiples tópicos que son simplemente imprescindibles para poder aplicarlas con éxito. Me estoy refiriendo a:

  • Programación en Silverlight 4.0“, de Marino Posadas (Netalia, ISBN 978-84-93489535). Una obra que, a pesar de su título, versa no solo sobre los temas más directamente relacionados con la programación en sí, sino también sobre los que tienen que ver con el diseño de interfaces de usuario; el capítulo dedicado a Expression Blend 4 es un buen ejemplo de ello. Esta edición no solo “toca” las nuevas características que se incorporaron por primera vez en la versión 4 de Silverlight (en particular, todo lo relacionado con la ejecución fuera del navegador), sino que además incluye un capítulo que describe los fundamentos del desarrollo de aplicaciones Silverlight para Windows Phone 7.
  • ADO.NET Entity Framework 4.0. Aplicaciones y servicios centrado en datos“, de Unai Zorrilla et al (Krasis Press, ISBN 978-84-93669676). Aunque, por razones obvias (le tengo mucho cariño a este libro, cuya primera versión ayudé a “traer al mundo”), puede que mi opinión no sea 100% imparcial, creo sinceramente que la presente edición mejora sensiblemente la original, complementando muchos de los temas originales, poniendo en su lugar a algunos de ellos que por aquel entonces se antojaban más relevantes, e incorporando excelentes presentaciones de prácticamente todas las nuevas características aparecidas con la versión 4.0. Otro gran “plus” de esta nueva edición es su mayor orientación práctica, con mejores ejemplos y un nuevo capítulo, “EF 4.0 en el mundo real”, dedicado a presentar las líneas generales del desarrollo de aplicaciones corporativas en múltiples capas basadas en EF 4.0 a través de un ejemplo disponible en Codeplex.

En resumen, dos excelentes obras, que recomiendo de corazón desde aquí a los lectores.

NOTA: Las opiniones reflejadas en este artículo son mías propias, y no han sido revisadas ni aprobadas por la empresa en la que trabajo.


Referencia musical: Para mí, el lugar que ocupa “The Dark Side of the Moon” (1973) en el mapa de la cultura popular occidental contemporánea lo define una estadística: 741 (me apasionan las estadísticas; tal vez por eso sea que me aferro desesperadamente al béisbol, en estos tiempos en que arrasan el soccer y el fútbol americano). 741 es el número de semanas consecutivas que estuvo “La cara oculta” en la lista Billboard de los 200 álbumes más vendidos (entre 1973 y 1988). Fueron más de 14 años, casi el doble de lo que hayan logrado alcanzar sus más cercanos perseguidores. Y ello, a pesar de no tratarse de un producto fabricado para el consumo fácil, estrictamente hablando. Un disco simplemente imprescindible, al igual que la mayoría de los demás trabajos de la banda, como “Wish You Were Here” (1975) o “The Wall” (1979).

Despedida como MVP

“Es de bien nacidos ser agradecidos”
(Refrán que me enseñó mi abuela Guillermina)

Este post está listo desde hace algunos días, pero decidí posponer su publicación hasta que salieran de la lista de los más leídos los posts de júbilo de mis compañeros que muy merecidamente han sido renovados por un año más o elegidos como MVP por primera vez, para no restarles protagonismo.

En mi caso, dejé de pertenecer al programa MVP el pasado 1 de enero. Y lo primero que debo dejar claro es que la decisión fue 100% correcta. He estado casi todo el año fuera de España, sin participar en las actividades de la comunidad. Por otra parte, he estado envuelto en un proyecto apasionante, aprendiendo un montón de cosas nuevas, y lo poco que podía haber hecho para haber merecido tal vez una renovación como MVP, simplemente quedó relegado a un plano secundario. Me refiero, por ejemplo, a cosas como publicar una versión actualizada a C# 4.0 del libro “C# 3.0 y LINQ”, o haber ayudado a mi buen amigo Unai en su excelente actualización del libro de Entity Framework a la versión 4.0 (que ya tengo por aquí; pienso escribir sobre él en los próximos días, tan pronto lo termine de leer). Así que, totalmente, Mea culpa.

Más allá de las florituras, el objetivo de este post es uno solo: expresar mi agradecimiento infinito a Microsoft por haberse fijado en mí por allá por 2004 y hacerme miembro del programa. La gran mayoría de las cosas buenas que han ocurrido en mi vida profesional a partir de entonces tienen que ver, de forma u otra, con esa decisión. En específico, quiero dar las gracias a los dos MVP Lead con los que tuve el honor de interactuar, Cristina González Herrero y Alberto Amescua Bernier, dos personas y profesionales “como la copa de un pino” que se desvivieron siempre a diario por transmitir nuestras quejas, opiniones y sugerencias a los equipos de producto, ponernos en contacto con las personas adecuadas dentro de esa gran empresa, y hacer otros miles de cosas más para que nuestra experiencia de MVP fuera lo más completa posible. Desde aquí les mando un fuerte abrazo, así como a todos los colegas MVP y empleados de Microsoft a los que he tenido el placer de conocer durante este hermoso viaje. Un afectuoso saludo también para los recién elegidos; me agrada sobremanera ver que el programa se rejuvenece y los “mayores” (como yo :-)) van cediendo el protagonismo a las caras jóvenes. Se me antoja que nadie como los cubanos debemos tener clara la importancia de la alternancia y la renovación para la vitalidad de cualquier proyecto.

¡Seguimos en contacto!

NOTA: Las opiniones reflejadas en este artículo son mías propias, y no han sido revisadas ni aprobadas por la empresa en la que trabajo.


Referencia literaria: “Mea culpa” es un libro muy recomendable de uno de mis escritores favoritos, Guillermo Cabrera Infante. Nadie ha sabido captar como él el embrujo de mi Habana natal, esa Habana que persigue en los sueños a los habaneros por muchas décadas que hayan transcurrido desde que te escapaste (¿intentaste escapar?) de allí. Y ya que hablamos sobre Premios Nobel de Literatura, no se pierda el reciente discurso de aceptación del premio de otro gigante de las letras ibero-americanas, Mario Vargas Llosa, disponible aquí.