"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í. 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.

Publicado por Octavio Hernández | con no comments
Archivado en:

"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.

Publicado por Octavio Hernández | con no comments
Archivado en:

[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)

Publicado por Octavio Hernández | con no comments
Archivado en: ,

"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ú".

Publicado por Octavio Hernández | con no comments
Archivado en:

"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).

Publicado por Octavio Hernández
Archivado en:

"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í.

Publicado por Octavio Hernández | 23 comment(s)
Archivado en:

"It was the heat of the moment
Telling me what my heart meant..."
("Heat of the Moment", Asia, 1982)

Mirando los vídeos del evento Silverlight Firestarter (todos accesibles desde aquí), se me ocurre que las palabras de Bob Muglia, pronunciadas (espero) en el calor del momento, ayudaron a fin de cuentas a llamar la atención sobre Silverlight y sobre este excelente evento...

Han corrido ríos de tinta con relación a esas declaraciones, pero si quiere leer aún algo más sobre el tema, puedo recomendarle los dos siguientes artículos:

  • "¿Silverlight vs HTML5? ¿Son buenos los estándares?", de mi maestro y amigo Miguel Katrib, disponible aquí.
  • "El caso SilverGate", de Braulio Díez y Reyes García, en la dotNetManía de este mes (nº 76). Este artículo incluye además referencias a las declaraciones de los principales actores que estuvieron implicados en el drama.

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.


Pop/Rock tip: A principios de los '80, los grandes grupos de rock progresivo empezaron a desintegrarse bajo los influjos de la comercialización: era demasiado el dinero que se ganaba "vendiendo el alma al diablo" y dedicándose a interpretar productos mucho más asequibles al "gran público". Comienzan entonces a surgir proyectos comerciales (¿super-grupos?) orientados a explotar las imágenes individuales de sus integrantes, a la misma vez que interpretando principalmente baladas y otros temas "suaves" capaces de subir a lo más alto de las listas de éxitos. Uno de los primeros representantes de esta tendencia fue Asia, banda en la que confluyeron John Wetton (King Crimson), Steve Howe y Geoff Downes (Yes) y Carl Palmer (Emerson, Lake & Palmer). "Heat of the Moment", de su primer disco (llamado tambien "Asia"), fue su primer gran éxito.

Publicado por Octavio Hernández | con no comments
Archivado en:

"Parallel our sights
And we will find, that we need to be where we belong
Parallel our heights
Display our rights and wrongs, and always keep it strong."
("Parallels", Yes, 1977)

Después de un buen tiempo sin escribir, "rumiando" a cada rato contra la incorporación a C# del tipado dinámico y toda la parafernalia asociada, a los que sigo aún sin encontrarles la "razón de estar" (ciertos anuncios recientes parecen hasta darme la razón), la presentación de la nueva Async CTP durante la PDC 2010 ha venido a insuflarme espíritu y confianza en que no todo está perdido y quedan muchas cosas interesantes aún por venir en relación con mi lenguaje favorito. Pero el lector no debería hacerme mucho caso en lo relativo a dynamic: creo que desde hace algún tiempo me estoy haciendo conservador (aunque, pienso, sin traspasar aún la delgada línea que separa "conservador" de "reaccionario" ;-). Es algo que pensé que jamás podría ocurrirme a mí, educado en la falacia bajo el signo de la "revolución interminable"; probablemente cosas de la edad :-).

En cuanto a la recién publicada Async CTP, pienso que se trata de una propuesta excelente, que simplificará en gran medida la programación asíncrona, cuya complejidad de implementación con la versión actual de C# es alta, algo de lo que puede dar fe cualquiera que se haya enfrentado al desarrollo de una aplicación medianamente "concurrente". A través de la introducción de dos nuevas palabras reservadas, async y await, la programación asíncrona en futuras versiones de C# se hará casi tan clara y natural como la síncrona, dejando al compilador la tarea de generar prácticamente todo el código de fontanería asociado al tratamiento de los callbacks y aprovechando al máximo las bondades que ofrece la Task Parallel Library (TPL) introducida en .NET 4.0.

Para descargar la CTP y acceder a una gran cantidad de documentación y ejemplos (incluyendo un vídeo introductorio de Anders Hejlsberg), visite http://msdn.microsoft.com/en-us/async.

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.


Pop/Rock tip: Para esta ocasión, he utilizado un tema de uno de los "padres" del rock progresivo, Yes; una banda que dura ya más de 40 años, durante los cuales, a pesar de los numerosos cambios de personal, ha sido capaz de mantener en todo momento un altísimo nivel interpretativo. Mis álbumes favoritos de Yes son los pertenecientes al primer ciclo de la banda, uno de cuyos máximos exponentes es "Going for the One" (1977); álbum al que pertenece el tema "Parallels".

Publicado por Octavio Hernández | 4 comment(s)
Archivado en: ,

En un interesante post (como siempre), el genial Eric Lippert muestra cómo generalizar el cálculo de n productos cartesianos utilizando LINQ. Creo haber estado entre los primeros que identificó el operador SelectMany de LINQ con el cálculo de un producto cartesiano, por allá por 2007 (parece que haya pasado una eternidad :-).

Publicado por Octavio Hernández | con no comments
Archivado en: ,

Visual Studio Languages Community Program Manager Lisa Feigenbaum has published in her blog (with the kind permission of dotNetManía) the English version of the interview I did for the magazine with Raj Pai, Group Program Manager of the Visual Studio Languages Team at Microsoft. The interview was originally published (in Spanish) in the recent special issue dedicated to Visual Studio 2010; in it, the conversation mainly revolves around this version's new features across the different supported programming languages, and then there's some more. Enjoy!

Publicado por Octavio Hernández | con no comments
Archivado en: ,

"We gotta move out
'Cause the city's movin' in..."
("Movin' out", Aerosmith, 1973)

Después de unos días en primera plana del C# Developer Center de MSDN, mi artículo corto "Solving Combinatory Problems with LINQ" sale de la lista de novedades, desplazado con toda justicia por ese suceso histórico que es la aparición de .NET Framework 4 y Visual Studio 2010:


Pop/Rock tip: Otro de los monstruos del rock que ha sobrevivido hasta el presente es Aerosmith, un grupo que no necesita presentación entre los que tienen 50 ó menos :-). "Movin' out" es un tema de su primer álbum, "Aerosmith" (1973), con el que sentaron las bases para los que vendrían después, de los que recomiendo especialmente los que considero sus dos mejores trabajos, "Toys in the Attic" (1975) y "Rocks" (1976).

Publicado por Octavio Hernández | con no comments
Archivado en: ,,

Unos días después de ver la luz el artículo "Tuplas en .NET Framework 4", que co-escribí para dotNetManía con mi maestro y amigo Miguel Katrib en el marco del ejemplar especial dedicado a la salida de .NET Framework 4 y Visual Studio 2010, me encuentro con este post de Jared Parsons, miembro del Languages Team de Microsoft, en el que se describe un posible escenario de utilización de las tuplas para suplir las carencias actuales de los tipos anónimos, con un espíritu muy similar al que presentamos en nuestro artículo. ¡Recomendado!

Publicado por Octavio Hernández | 2 comment(s)
Archivado en: ,,

"Standing on a bridge, watch the water passing under me
It must’ve been much harder when there was no bridge just water..."
("Funny the Way it is", Dave Matthews Band, 2009)

Ayer se publicó en el área de Community Content de MSDN mi artículo corto "Solving Combinatory Problems with LINQ", un divertimento basado en LINQ al estilo de otros que ya he publicado tanto en "C# 3.0 y LINQ" como aquí. Estos puzzles siempre me traen a la memoria los problemas que poníamos a nuestros alumnos hace veintitantos años en la Universidad de La Habana, y me hacen pensar en cómo el progreso hace fácil lo que un tiempo atrás era bastante más difícil, que es precisamente a lo que se hace alusión en la referencia musical de hoy.


Pop/Rock tip: De entre los grupos contemporáneos de música popular, uno de los que más me gustan por su calidad, originalidad y eclecticismo es Dave Matthews Band. Su música es una interesante combinación de rock, jazz, soul, bluegrass e incluso música clásica, y en sus conciertos acostumbran a improvisar alrededor de sus canciones al estilo de las jam sessions tan típicas del jazz. "Funny the Way it is" fue el primer single del disco "Big Whiskey and the GrooGrux King" (2009), que vi por primera vez (y no dejé escapar :-) en un Starbucks, a mediados del año pasado.

Publicado por Octavio Hernández | 3 comment(s)
Archivado en: ,,

Vuelvo de nuevo a la carga para resaltar los principales contenidos que ofrece el más reciente número de la revista dotNetManía, en esta ocasión dedicado casi íntegramente al suceso más importante del año en lo que a la plataforma .NET se refiere: la salida de .NET Framework 4 y Visual Studio 2010.

Como artículo de portada, este mes se ofrece "Programación paralela con VS 2010 y .NET Framework 4", de Leonardo Paneque y Miguel Katrib, una introducción seria a las principales puertas que se abren ante nosotros con las nuevas versiones para aprovechar la potencia de los ya quasi-omnipresentes múltiples núcleos y procesadores; también en relación con las nuevas posibilidades de las librerías, Javier Holguera presenta "Novedades en WCF 4". En el área de los lenguajes de programación, Luis Miguel Blanco describe las novedades de Visual Basic 10, mientras que Marino Posadas se encarga de la presentación ante el público del nuevo lenguaje que se añade a la familia en esta versión con el artículo "F#: un mundo de posibilidades". Para no olvidar al entorno de desarrollo en sí, Bruno Capuano describe una de las novedades más destacadas al respecto: la depuración histórica. Finalmente, Alberto Población da respuesta a varias de las preguntas relacionadas con las nuevas versiones que con más frecuencia se repiten en los foros de desarrollo.

En lo personal, este mes he tenido la ocasión (y el honor) de co-escribir el artículo "Tuplos en .NET Framework 4" con mi maestro y amigo Miguel Katrib; no escribíamos nada juntos desde 1991, cuando publicamos, para la institución que considero mi Alma Máter, la Universidad de La Habana, un cuaderno de "Ejercicios de programación en Pascal" que guardo "bajo un cristal" - los cubanos sabrán a qué me refiero. Espero que los lectores nos disculpen el uso del término "tuplos" en lugar del comúnmente utilizado en la península ibérica "tuplas" - un pequeño, pero sentido homenaje al sitio del que provenimos.


Notas culturales: En esta ocasión, la referencia musical está en el propio título del post. "There's Know Place Like Home" (2009) es el título del último doble-CD y DVD de mi banda favorita, Kansas, en el que volvieron a su ciudad natal, Topeka (¿o es Google?), para grabar un concierto en directo con una orquesta sinfónica local. Como seguramente sabrá, "There's no place like home" es una frase de Dorothy, la niña protagonista de "El mago de Oz", que era precisamente de Kansas; el trueque de "no" por "know" es una "marca registrada" de la banda, que aplicó la fórmula por primera vez en el famoso disco "Point of Know Return" (1977). En plena adolescencia, este disco me enseñó cómo bastan dos letras para transformar la negación en certeza y la desesperación en esperanza.

Por otra parte, "guardados bajo un cristal" es un verso de un poema de nuestro héroe nacional José Martí, "Los zapaticos de rosa", que todo cubano se sabe desde la infancia. Desde aquí las gracias a mi buena amiga Marta Polanco, de quien tomé prestada la idea de usar un verso de este poema del Maestro.

 

Publicado por Octavio Hernández | con no comments
Archivado en:

"'I'm older now, and still runnin'
Against the wind"
("Against the Wind", Bob Seger, 1980)

Después de muchos meses sin escribir prácticamente nada (C# y el inglés no cuentan), retorno este mes a dotNetManía con una entrevista al gran Jeffrey Richter, que acaba de publicar una nueva edición (la 3ra., actualizada para .NET Framework 4 y C# 4.0) de su excelente libro "CLR via C#".

Por otra parte, este ejemplar, que recomiendo de corazón a los lectores, incluye excelentes artículos como "Tipado dinámico en C# 4.0", de Mario del Valle y Miguel Katrib, que resume de manera perfecta los fundamentos de esta nueva posibilidad que se abre ante los desarrolladores de C# y que ciertos ortodoxos (como yo :-) aún no acaban de aceptar del todo, y "Acceso a datos en Silverlight con WCF RIA Services", de Luis Miguel Blanco, que le permitirá "ponerse en órbita" rápidamente en todo lo relativo a la creación y consumo de este novedoso tipo de servicios.

¡No se lo pierda!

Pop/Rock tip: Esta vez la referencia musical va dedicada a mi buen amigo Paco Marín, que no ceja en su empeño de llevar a los lectores mes tras mes una publicación impresa de calidad.

Bob Seger es uno de los intérpretes más destacados de lo que hoy se denomina rock clásico, y varios de sus temas, como el aquí mencionado "Against the Wind", pero también "Mainstreet", "Night Moves", "Hollywood Nights" o "Turn the Page" (aunque este último probablemente es más conocido en la versión que hizo años después Metallica), pueden aún oírse con frecuencia en diferentes medios. Es de destacar también que "Against the Wind" forma parte de la banda sonora de ese gran caleidoscopio de la cultura popular norteamericana de la época que es la película "Forrest Gump".

Post Scriptum. Me alegra ver cómo la idea de asociar una referencia cultural a los posts, que yo copié de Pablito, va tomando cierta fuerza. Ultimamente he visto hacerlo a amigos como Gustavo Vélez o Eugenio Estrada, e incluso ¡al mismísimo Eric Lippert, del equipo de C#! En mi opinión, de esta manera los posts ayudan a difundir cultura en general, y no solamente cultura informática.

Publicado por Octavio Hernández | 4 comment(s)
Archivado en: ,

[1] "'Cause rockin' and rollin' (and bloggin' - OH)
Is only howlin' at the moon..."
("Magnum Opus", Kansas, 1975)

[2] "You make loving (programming- OH) fun...
It's all I wanna do!"
("You make loving fun", Fleetwood Mac, 1977)

Salgo de mi cueva para aullar [1] un poco, en esta ocasión para recomendar a mis lectores el artículo "Programación por Contratos. Un deseo hecho realidad", de Miguel Katrib y Jorge Luis de Armas (dotNetManía nº 65), que resume de manera excelente (en unas 12 páginas, bastante más de lo habitual para un artículo de la revista) lo que representa y aporta la incorporación de Code Contracts a la próxima versión 4.0 de .NET Famework. El Maestro no necesita presentación alguna; de Jorge Luis (de quien tuve el honor de ser tutor de su trabajo de tesis hace ya más de una década) baste decir que, amén de excelente persona y profesional, tiene el privilegio de haber sido el primer  cubano en ganar un primer premio en una olimpiada mundial internacional de Matemáticas.

Con la adición de Code Contracts a la librería de clases de .NET (a lo que muy probablemente seguirá la adición de las correspondientes instrucciones en futuras versiones de C# y VB), Microsoft definitivamente ha cumplido un sueño de mucha gente a lo largo de mucho tiempo, y sin duda nos hará la programación mucho más amena y divertida [2] en el futuro. 


 Pop/Rock tip: Como de mi banda favorita, Kansas, y uno de mis álbumes favoritos, Leftoverture (1975), ya he hablado y seguramente volveré a hablar aquí, esta vez toca presentar (si es que el término es adecuado) a Fleetwood Mac.

Mike Fleetwood y John McVie ya se habían ganado un espacio en la historia del rock desde finales de los '60 con temas como "Albatross"; pero en 1975 dieron un giro espectacular a su carrera e incorporaron al grupo a dos fenomenales compositores e intérpretes: Stevie Nicks (su tema "Landslide" es de los que no se olvidan) y Lindsey Buckingham. Ya desde antes formaba parte de la banda Christine McVie, esposa entonces de John. El primer álbum con esta nueva formación, "Fleetwood Mac" (1975), sentó las bases para lo que vendría después: el "Rumours" (1977), que tomó por asalto el circuito comercial y no paró hasta convertirse en el disco más vendido de todos los tiempos, récord que solo cederían años después al "Thriller" del recientemente fallecido Michael Jackson. De aquella época recuerdo cómo desfilaron por lo más alto del American Top Forty temas como "Don't Stop", "Dreams", "You Make Lovin' Fun" y "Go Your Own Way", en un "quítate tu, pa' ponerme yo" que no se recordaba desde la época de los Beatles. ¡Y eso que, como ocurre casi siempre, las mejores canciones del disco, que hoy son clásicos del rock (me refiero a temas como "The Chain" o "Second Hand News") no fueron catalogadas como singles! En mi opinión, un ejemplo de éxito comercial avalado por calidad. Y un puñado de canciones que aún suenas frescas más de treinta años después. Recomendado.

Publicado por Octavio Hernández | 4 comment(s)
Archivado en:

"Now I know you're all king horse
Between tenderness and brute force..."
("King Horse", Elvis Costello, 2007)

Continuando con el problema propuesto en el post anterior (basado en "El símbolo perdido", la última obra de Dan Brown), aquí presento el código final utilizado para resolver el problema, así como un análisis somero de los resultados obtenidos.

La adición de las condiciones que faltan al programa del post anterior (que la suma de los cuatro "cuadrantes", más la del cuadrado central, coincida con la de las filas, columnas y diagonales) nos permite reducir el número de "variables libres" sobre las que el programa debe iterar a 7, con lo que la cantidad de combinaciones a probar es del orden de MAX^7, donde MAX es el valor máximo que queremos poder almacenar en cualquier casilla.Inicialmente establecí MAX a 100, con lo que el número de combinaciones a intentar era realmente enorme. Pero el problema resultó más "flojo" de lo que pensaba: en unos dos días de cálculo ininterrumpido, Rainmaker ya había encontrado unas 500.000 soluciones, y el valor de la primera variable (a11) aún seguía siendo 1. Así que decidí no torturar más al pobre amigo y detuve la ejecución. A continuación, el primero de los cuadrados obtenidos:

1 4 11 29
26 14 3 2
12 7 21 5
6 20 10 9

Entonces decidí restringir la búsqueda a los cuadrados en los que el número máximo utilizado fuera el 20, lo que redujo considerablemente la cantidad de combinaciones a probar. En algo menos de un minuto, ya tenía a mi disposición los 320 cuadrados válidos existentes. De nuevo, aquí solo muestro el primero de ellos; el lector interesado en buscar uno más "bonito" puede ejecutar el programa y estudiar sus resultados.

11 1 13 19
18 14 4 8
3 9 17 15
12 20 10 2

Así que aquí está mi modesto homenaje a Visual Studio 2010 - un programa que utiliza LINQ y que se me antoja combina, usando las palabras de Elvis Costello, "ternura y fuerza bruta" (pero, ¿en qué medida cada una de ellas, amigo lector? :-) .

Código utilizado:

using System;
using System.IO;
using System.Linq;

namespace LostSymbol
{
    class Program
    {
        private const int MAX = 20;

        static void Main(string[] args)
        {
            const int firstSeed = 20;
            const int secondSeed = 10;

            var res =
                /* first row */
                from a11 in Enumerable.Range(1, MAX)
                where a11 != firstSeed && a11 != secondSeed
                from a12 in Enumerable.Range(1, MAX)
                where a12 != firstSeed && a12 != secondSeed &&
                      a12 != a11
                from a13 in Enumerable.Range(1, MAX)
                where a13 != firstSeed && a13 != secondSeed &&
                      a13 != a11 && a13 != a12
                from a14 in Enumerable.Range(1, MAX)
                where a14 != firstSeed && a14 != secondSeed &&
                      a14 != a11 && a14 != a12 && a14 != a13
                let sum = a11 + a12 + a13 + a14
                /* second row */
                from a21 in Enumerable.Range(1, MAX)
                where a21 != firstSeed && a21 != secondSeed &&
                      a21 != a11 && a21 != a12 && a21 != a13 && a21 != a14
                let a22 = sum - (a11 + a12 + a21)
                where a22 > 0 && a22 <= MAX &&
                      a22 != firstSeed && a22 != secondSeed &&
                      a22 != a21 &&
                      a22 != a11 && a22 != a12 && a22 != a13 && a22 != a14
                from a23 in Enumerable.Range(1, MAX)
                where a23 != firstSeed && a23 != secondSeed &&
                      a23 != a21 && a23 != a22 &&
                      a23 != a11 && a23 != a12 && a23 != a13 && a23 != a14
                let a24 = sum - (a21 + a22 + a23)
                where a24 > 0 && a24 <= MAX &&
                      a24 != firstSeed && a24 != secondSeed &&
                      a24 != a21 && a24 != a22 && a24 != a23 &&
                      a24 != a11 && a24 != a12 && a24 != a13 && a24 != a14 &&
                      a13 + a14 + a23 + a24 == sum     /* second quadrant */ 
                /* third row */
                from a31 in Enumerable.Range(1, MAX)
                where a31 != firstSeed && a31 != secondSeed &&
                      a31 != a11 && a31 != a12 && a31 != a13 && a31 != a14 &&
                      a31 != a21 && a31 != a22 && a31 != a23 && a31 != a24
                let a32 = sum - (a12 + a22 + firstSeed)
                where a32 > 0 && a32 <= MAX &&
                      a32 != firstSeed && a32 != secondSeed &&
                      a32 != a31 &&
                      a32 != a11 && a32 != a12 && a32 != a13 && a32 != a14 &&
                      a32 != a21 && a32 != a22 && a32 != a23 && a32 != a24
                let a33 = sum - (a13 + a23 + secondSeed)
                where a33 > 0 && a33 <= MAX &&
                      a33 != firstSeed && a33 != secondSeed &&
                      a33 != a31 && a33 != a32 &&
                      a33 != a11 && a33 != a12 && a33 != a13 && a33 != a14 &&
                      a33 != a21 && a33 != a22 && a33 != a23 && a33 != a24 &&
                      a22 + a23 + a32 + a33 == sum     /* middle quadrant */
                let a34 = sum - (a31 + a32 + a33)
                where a34 > 0 && a34 <= MAX &&
                      a34 != firstSeed && a34 != secondSeed &&
                      a34 != a31 && a34 != a32 && a34 != a33 &&
                      a34 != a11 && a34 != a12 && a34 != a13 && a34 != a14 &&
                      a34 != a21 && a34 != a22 && a34 != a23 && a34 != a24
                /* fourth row */
                let a41 = sum - (a11 + a21 + a31)
                where a41 > 0 && a41 < MAX &&
                      a41 != firstSeed && a41 != secondSeed &&
                      a41 != a11 && a41 != a12 && a41 != a13 && a41 != a14 &&
                      a41 != a21 && a41 != a22 && a41 != a23 && a41 != a24 &&
                      a41 != a31 && a41 != a32 && a41 != a33 && a41 != a34 &&
                      a41 + a32 + a23 + a14 == sum &&    /* right-to-left diagonal */
                      a31 + a32 + a41 + firstSeed == sum     /* fourth quadrant */
                let a42 = firstSeed
                let a43 = secondSeed
                let a44 = sum - (a14 + a24 + a34)
                where a44 > 0 && a44 < MAX &&
                      a44 != firstSeed && a44 != secondSeed &&
                      a44 != a41 &&
                      a44 != a11 && a44 != a12 && a44 != a13 && a44 != a14 &&
                      a44 != a21 && a44 != a22 && a44 != a23 && a44 != a24 &&
                      a44 != a31 && a44 != a32 && a44 != a33 && a44 != a34 &&
                      a41 + firstSeed + secondSeed + a44 == sum &&
                      a11 + a22 + a33 + a44 == sum &&    /* left-to-right diagonal */
                      a33 + a34 + a43 + a44 == sum     /* third quadrant */
                select new
                {
                    a11, a12, a13, a14,
                    a21, a22, a23, a24,
                    a31, a32, a33, a34,
                    a41, a42, a43, a44,
                };

            using (StreamWriter sw = new StreamWriter("C:\\TEMP\\Solutions.txt"))
            {
                sw.WriteLine("Start : " + DateTime.Now.ToString("yyyy/MM/dd hh:mm:ss"));
                int n = 0;
                foreach (var r in res)
                {
                    sw.WriteLine("Solution " + n);
                    sw.WriteLine("=============");
                    sw.WriteLine("{0} {1} {2} {3}", r.a11, r.a12, r.a13, r.a14);
                    sw.WriteLine("{0} {1} {2} {3}", r.a21, r.a22, r.a23, r.a24);
                    sw.WriteLine("{0} {1} {2} {3}", r.a31, r.a32, r.a33, r.a34);
                    sw.WriteLine("{0} {1} {2} {3}", r.a41, r.a42, r.a43, r.a44);
                    sw.WriteLine();
                    sw.Flush(); n++;
                }
                sw.WriteLine("Finish: " + DateTime.Now.ToString("yyyy/MM/dd hh:mm:ss"));
            }
            Console.ReadLine();
        }
    }
}


Pop/Rock tip: Elvis Costello, cantante y compositor nacido en Inglaterra, lleva más de treinta años de éxito desde que debutó en 1977 con el excelente album "My Aim is True". Su eclecticismo musical y letras trabajadas lo han convertido en un referente para varias generaciones de músicos.

Publicado por Octavio Hernández | 2 comment(s)
Archivado en: ,,

Últimamente he estado leyendo en los ratos libres "El símbolo perdido", la última obra de Dan Brown, el autor de "El código Da Vinci" y otros best sellers. Como parte de los hechos a los que se enfrenta el protagonista durante sus peripecias para descifrar un oculto misterio, el autor nos presenta un cuadrado ultra-mágico que aparece en el cuadro "Melencolia I" (1514), del pintor alemán Alberto Durero:

16 3 2 13
5 10 11 8
9 6 7 12
4 15 14 1

La "magia" de este cuadrado (más información aquí) radica en el hecho de que no solo todas las filas, todas las columnas y las dos diagonales suman 34; adicionalmente, los cuatro "cuadrantes" del cuadrado también suman 34, así como las cuatro casillas centrales. Por último, las dos casillas centrales de la última fila son 15 y 14, que concatenadas producen '1514', el año en el que Durero pintó el cuadro.

En cierto momento de la lectura, pensé: ¿y por qué no buscar un cuadrado similar, pero que tenga en esas casillas inferiores '20' y '10' (en homenaje, claro está, a Visual Studio 2010 :-)? La siguiente pregunta surgió casi inmediatamente: ¿y por qué no utilizar LINQ, que es parte del producto y de seguro nos permitirá especificar el problema de una manera natural, para resolverlo?

Al final de este post incluyo el código que escribí en pocos minutos para resolver una simplificación del problema que me pareció ya bastante difícil: simplemente buscar un cuadrado tal, que todas las filas, columnas y diagonales sumen lo mismo, con '20' y '10' en las casillas centrales inferiores. Pensé que encontrar una solución tal podía requerir un enorme tiempo de cálculo en el peor de los casos dada la complejidad algorítmica del programa. Pero como últimamente mi viejo amigo Rainmaker (llamado así, por supuesto, en honor a un tema de Kansas) se pasa los días ocioso y solito en casa, ¿por qué no intentarlo y de paso alegrarle un poco la vida?

Al final, la simplificación resultó ser mucho menos dura de lo que pensaba, y a los pocos minutos el programa estaba escupiendo respuestas con cierta frecuencia. A continuación, la primera de las soluciones encontradas:

1 2 15 29
14 21 5 7
23 4 17 3
9 20 10 8

Por supuesto, este cuadrado no cumple con todas las condiciones del cuadrado de Durero. Desde aquí invito a los lectores a completar mi programa con las condiciones que faltan o crear el suyo propio y buscar un cuadrado que cumpla todas las condiciones (si es que existe).

Sobre la utilización de LINQ para resolver problemas de este tipo ya escribí en su momento (http://geeks.ms/blogs/ohernandez/archive/2007/04/25/191-debemos-aprender-una-nueva-forma-de-escribir-bucles.aspx), aunque sigo teniendo algunas dudas existenciales al respecto :-). Un experimento que se me antoja interesante sería el de comparar el rendimiento de implementaciones como ésta al utilizar LINQ y PLINQ en máquinas con múltiples núcleos. Pero ese experimento, por mi parte, tendrá que esperar…

(Vea la continuación aquí)

Código utilizado:

using System;
using System.IO;
using System.Linq;

namespace LostSymbol
{
    class Program
    {
        private const int MAX = 100;

        static void Main(string[] args)
        {
            const int firstSeed = 20;
            const int secondSeed = 10;

            var res =
                /* first row */
                from a11 in Enumerable.Range(1, MAX)
                where a11 != firstSeed && a11 != secondSeed
                from a12 in Enumerable.Range(1, MAX)
                where a12 != firstSeed && a12 != secondSeed &&
                      a12 != a11
                from a13 in Enumerable.Range(1, MAX)
                where a13 != firstSeed && a13 != secondSeed &&
                      a13 != a11 && a13 != a12
                from a14 in Enumerable.Range(1, MAX)
                where a14 != firstSeed && a14 != secondSeed &&
                      a14 != a11 && a14 != a12 && a14 != a13
                let sum = a11 + a12 + a13 + a14
                /* second row */
                from a21 in Enumerable.Range(1, MAX)
                where a21 != firstSeed && a21 != secondSeed &&
                      a21 != a11 && a21 != a12 && a21 != a13 && a21 != a14
                from a22 in Enumerable.Range(1, MAX)
                where a22 != firstSeed && a22 != secondSeed &&
                      a22 != a21 &&
                      a22 != a11 && a22 != a12 && a22 != a13 && a22 != a14
                from a23 in Enumerable.Range(1, MAX)
                where a23 != firstSeed && a23 != secondSeed &&
                      a23 != a21 && a23 != a22 &&
                      a23 != a11 && a23 != a12 && a23 != a13 && a23 != a14
                let a24 = sum - (a21 + a22 + a23)
                where a24 > 0 && a24 <= MAX &&
                      a24 != firstSeed && a24 != secondSeed &&
                      a24 != a21 && a24 != a22 && a24 != a23 &&
                      a24 != a11 && a24 != a12 && a24 != a13 && a24 != a14
                /* third row */
                from a31 in Enumerable.Range(1, MAX)
                where a31 != firstSeed && a31 != secondSeed &&
                      a31 != a11 && a31 != a12 && a31 != a13 && a31 != a14 &&
                      a31 != a21 && a31 != a22 && a31 != a23 && a31 != a24
                let a32 = sum - (a12 + a22 + firstSeed)
                where a32 > 0 && a32 <= MAX &&
                      a32 != firstSeed && a32 != secondSeed &&
                      a32 != a31 &&
                      a32 != a11 && a32 != a12 && a32 != a13 && a32 != a14 &&
                      a32 != a21 && a32 != a22 && a32 != a23 && a32 != a24
                let a33 = sum - (a13 + a23 + secondSeed)
                where a33 > 0 && a33 <= MAX &&
                      a33 != firstSeed && a33 != secondSeed &&
                      a33 != a31 && a33 != a32 &&
                      a33 != a11 && a33 != a12 && a33 != a13 && a33 != a14 &&
                      a33 != a21 && a33 != a22 && a33 != a23 && a33 != a24
                let a34 = sum - (a31 + a32 + a33)
                where a34 > 0 && a34 <= MAX &&
                      a34 != firstSeed && a34 != secondSeed &&
                      a34 != a31 && a34 != a32 && a34 != a33 &&
                      a34 != a11 && a34 != a12 && a34 != a13 && a34 != a14 &&
                      a34 != a21 && a34 != a22 && a34 != a23 && a34 != a24
                /* fourth row */
                let a41 = sum - (a11 + a21 + a31)
                where a41 > 0 && a41 < MAX &&
                      a41 != firstSeed && a41 != secondSeed &&
                      a41 != a11 && a41 != a12 && a41 != a13 && a41 != a14 &&
                      a41 != a21 && a41 != a22 && a41 != a23 && a41 != a24 &&
                      a41 != a31 && a41 != a32 && a41 != a33 && a41 != a34 &&
                      a41 + a32 + a23 + a14 == sum     /* right-to-left diagonal */
                let a42 = firstSeed
                let a43 = secondSeed
                let a44 = sum - (a14 + a24 + a34)
                where a44 > 0 && a44 < MAX &&
                      a44 != firstSeed && a44 != secondSeed &&
                      a44 != a41 &&
                      a44 != a11 && a44 != a12 && a44 != a13 && a44 != a14 &&
                      a44 != a21 && a44 != a22 && a44 != a23 && a44 != a24 &&
                      a44 != a31 && a44 != a32 && a44 != a33 && a44 != a34 &&
                      a41 + firstSeed + secondSeed + a44 == sum &&
                      a11 + a22 + a33 + a44 == sum     /* left-to-right diagonal */
                select new
                {
                    a11, a12, a13, a14,
                    a21, a22, a23, a24,
                    a31, a32, a33, a34,
                    a41, a42, a43, a44,
                };

            using (StreamWriter sw = new StreamWriter("C:\\TEMP\\Solutions.txt"))
            {
                sw.WriteLine("Start : " + DateTime.Now.ToString("yyyy/MM/dd hh:mm:ss"));
                int n = 0;
                foreach (var r in res)
                {
                    sw.WriteLine("Solution " + n);
                    sw.WriteLine("=============");
                    sw.WriteLine("{0} {1} {2} {3}", r.a11, r.a12, r.a13, r.a14);
                    sw.WriteLine("{0} {1} {2} {3}", r.a21, r.a22, r.a23, r.a24);
                    sw.WriteLine("{0} {1} {2} {3}", r.a31, r.a32, r.a33, r.a34);
                    sw.WriteLine("{0} {1} {2} {3}", r.a41, r.a42, r.a43, r.a44);
                    sw.WriteLine();
                    sw.Flush(); n++;
                }
                sw.WriteLine("Finish: " + DateTime.Now.ToString("yyyy/MM/dd hh:mm:ss"));
            }
            Console.ReadLine();
        }
    }
}

Publicado por Octavio Hernández | 5 comment(s)
Archivado en: ,,

"I could change my life to better suit your mood
Because you're so smooth..."
("Smooth", Santana featuring Rob Thomas, 1999)

El presente post es para recomendar sinceramente a mis lectores el ejemplar de este mes de dotNetManía, en el que Miguel Katrib y Mario del Valle publican un excelente artículo sobre las futuras posibilidades asociadas a la varianza y contravarianza en los tipos genéricos que ofrecerá C# 4.0. Del artículo he tomado prestado el término "suave" (smooth), con el que los autores califican a la transición paulatina que hemos ido observando en el sistema de tipos de C# a partir de su versión original y en particular a partir de la versión 2.0, en la que apareció por primera vez la genericidad en el lenguaje.

Por demás, la edición de este mes incluye otros varios muy buenos artículos (escritos igualmente por grandes amigos como Marino Posadas o Iván González, entre otros) enmarcados en el contexto de un ejemplar dedicado a las recientemente aparecidas versiones 3 de Silverlight y Expression. Pensando en el caso de Silverlight, no estoy seguro de si me atrevería a describir precisamente como "suaves" las transiciones en su desarrollo, aunque no por ninguna razón técnica (¡todo lo contrario!), sino por la celeridad con la que las diferentes versiones del producto se han ido lanzando al mercado. 


 Pop/Rock tip: Carlos Santana es, sin duda alguna, uno de los guitarristas más destacados de toda la historia del rock. Temas como "Oye como va", "Samba pa' ti" o "Black Magic Woman" le abrieron un hueco en la historia de la música popular desde principios de los '70. Ya a finales del pasado milenio, "Supernatural" (1999), un álbum de colaboraciones con otras estrellas como Eric Clapton, Rob Thomas, Dave Matthews, Lauryn Hill o Maná, entre otros (y en el que tuvo alguna participación mi hermano), tomó por asalto los medios de todo el mundo. Según "The Billboard Book of Top 40 Hits", "Smooth" (tema que Rob Thomas compuso para su esposa, de origen portorriqueño) es el single de mayor éxito comercial de toda la historia. ¡Eso es Latino Power!

Publicado por Octavio Hernández | con no comments
Archivado en: ,

"Oh, give me land, lots of land under starry skies above,
Don't fence me in"
("Don't fence me in", Ella Fitzgerald, 1956)

"If you want to keep something precious
You got to lock it up and throw away the key
If you want to hold onto your possession
Don't even think about me"
("If you love somebody set them free", Sting, 1986)

Me escribe mi amigo Alain pidiéndome que comente acerca de la limitación de LINQ to SQL que le impide utilizar en sus modelos tablas que tengan una clave primaria autoincremental de tipo byte (TINYINT en SQL Server); el intento produce el error de ejecución "The primary key column of type 'TinyInt' cannot be generated by the server". Lamentablemente, no se me ocurre ninguna razón válida que ofrecerle, salvo la ya tradicional frase "By design", con la que generalmente los equipos de desarrollo quieren decir "Lo hicimos así por que nos salió de ..." (complete la frase el lector con la referencia corporal o espiritual que prefiera, aunque a fin de cuentas, el único culpable es el cerebro de alguien). La solución pasa por definir el campo de tipo SMALLINT (16 bits) en lugar de TINYINT pero, ¿si SQL Server soporta este tipo de campos, por qué eliminar la posibilidad en LINQ to SQL? Probablemente alguien, con toda la buena intención del mundo, decidió que, dado el estrecho rango que ofrece TINYINT, sería mejor prohibir la utilización de tales campos; pero, ¿qué saben los desarrolladores de librerías de los posibles usos que podrán tener en el futuro sus desarrollos?

Evitar la imposición de tales "cercas" ("vallas") artificiales es uno de los aspectos a tener muy en cuenta durante el desarrollo de librerías.

Nota adicional: He probado el mismo ejemplo bajo la Beta 1 de VS 2010 y comprobado que la situación se mantiene. Y en estos tiempos de costes ajustados y dada la particular relación entre LINQ to SQL y Entity Framework, lo más probable es que todo siga igual después de la salida de la nueva versión.


Pop/Rock tip: Esta vez introducimos el post con un fragmento de un tema clásico de Cole Porter que oímos por primera vez en la voz de la inmortal Ella Fitzgerald, una que nunca faltaba en nuestra casa de La Habana. Adicionalmente va otra referencia alegórica al tema de hoy: "If you love somebody set them free", de aquel genial Sting que, después de romper con Police, conformó una banda espectacular con músicos afro-norteamericanos (el fallecido Kenny Kirland al piano, Branford Marsalis al clarinete, Darryl Jones al bajo y Omar Hakim en la batería, entre otros) de la que hoy quedan como recuerdo los álbumes "The Dream of the Blue Turtles" (1985) y "Bring on the Night" (1986).

Publicado por Octavio Hernández | 1 comment(s)
Archivado en:
Más artículos Página siguiente >