<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-22471446</id><updated>2012-01-04T09:58:30.511+01:00</updated><category term='AOP'/><category term='destructor'/><category term='CLR'/><category term='atributos'/><category term='SQL'/><category term='ray tracing'/><category term='debugging'/><category term='geometría'/><category term='hilos'/><category term='Brasil'/><category term='AJAX'/><category term='RPC'/><category term='personajes'/><category term='yo'/><category term='ASP.NET'/><category term='extension methods'/><category term='interface'/><category term='C++'/><category term='blob'/><category term='MSDN'/><category term='programación funcional'/><category term='Marteens'/><category term='libros'/><category term='controles'/><category term='sintaxis'/><category term='concurrencia'/><category term='Delphi'/><category term='remoting'/><category term='COM+'/><category term='metodología'/><category term='boxing'/><category term='WinAPI'/><category term='Design by Contract'/><category term='XSight'/><category term='LINQ'/><category term='Windows Forms'/><category term='náusea'/><category term='bloqueos'/><category term='óptica'/><category term='optimización'/><category term='bases de datos'/><category term='sincronización'/><category term='ideas'/><category term='koan'/><category term='ADO.NET'/><category term='Mr. Butters'/><category term='C#'/><category term='disparates'/><category term='Freya'/><category term='descargas'/><category term='generics'/><category term='OOP'/><category term='EF'/><category term='cargocultismo'/><category term='cursos'/><category term='.NET'/><category term='trabajo'/><title type='text'>Comma NET</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default?start-index=101&amp;max-results=100'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>156</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-22471446.post-5450627627003888419</id><published>2010-10-26T00:41:00.003+02:00</published><updated>2010-10-26T00:48:21.128+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='descargas'/><category scheme='http://www.blogger.com/atom/ns#' term='Delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='libros'/><category scheme='http://www.blogger.com/atom/ns#' term='Marteens'/><title type='text'>La Cara Oculta de Delphi 6</title><content type='html'>&lt;div&gt;&lt;span class="first"&gt;Todo hombre de&lt;/span&gt; negocios sabe que no debe regalar aquello que puede vender. Todo hombre de negocios inteligente sabe, además, que no debe tirar aquello que puede regalar.&lt;/div&gt;&lt;div&gt;"La Cara Oculta de Delphi 6" es un libro al que profeso mucho cariño. Invertí en su preparación muchas horas, me sirvió para afianzar mi empresa... y estoy satisfecho con el resultado. Pero ya ha pasado tiempo suficiente como para dar por cerrada una etapa profesional, y para pasar a la siguiente. Aquí está la versión electrónica del libro, por si a alguien todavía le interesa:&lt;/div&gt;&lt;ul type="square"&gt;&lt;li&gt;&lt;a href="http://www.marteens.com/pdfs/TheDarkSideOfDelphi6.pdf" target="_blank" title="PDF (7MB)"&gt;La Cara Oculta de Delphi 6&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Es tiempo de ascender otro escalón...&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-5450627627003888419?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/5450627627003888419/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=5450627627003888419&amp;isPopup=true' title='34 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/5450627627003888419'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/5450627627003888419'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2010/10/la-cara-oculta-de-delphi-6.html' title='La Cara Oculta de Delphi 6'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>34</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-7347546949860864704</id><published>2010-09-08T00:18:00.020+02:00</published><updated>2010-09-08T02:47:48.029+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='WinAPI'/><category scheme='http://www.blogger.com/atom/ns#' term='controles'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows Forms'/><title type='text'>Cómo espiar los mensajes de un control</title><content type='html'>&lt;div&gt;&lt;img style="float:right; margin:1px 0 1px 8px; border-style:none;" src="http://4.bp.blogspot.com/_QWaXq7W8dVI/TIa7P8vEPWI/AAAAAAAAARU/5okcoM8XOco/s320/spyingmsgs.jpg" border="0" alt="Esto es lo que se ve al espiar ciertas ventanas" /&gt;&lt;span class="first"&gt;Sigo con trucos necesarios para&lt;/span&gt; implementar un sistema de gestión de ventanas más o menos complejo. Imagine que tiene un botón, y que debe responder a los clics del mismo. Ni lo piense: desde la ventana, o desde la clase que contiene al botón, añade un manejador al evento &lt;i&gt;Click&lt;/i&gt; del botón. Esta es una ventaja que tiene .NET y su sistema de eventos &lt;i&gt;multicast&lt;/i&gt; sobre el viejo y más sencillo sistema de eventos de Delphi nativo. En Delphi nativo solamente podíamos asociar un único manejador a cada evento. En .NET, el evento puede disparar cuantos manejadores necesitemos.&lt;/div&gt;&lt;div&gt;La gran pregunta: ¿y qué ocurre si lo que quiero interceptar es un mensaje que no tiene un evento de "alto nivel" asociado? La solución "clásica" es crear una clase derivada a partir del botón. Pero, ¿y si no es posible hacerlo? Por ejemplo, puede que le toque lidiar con un botón que usted &lt;i&gt;no ha creado&lt;/i&gt; (la culpa siempre es de otro). En mi caso, no se trata de un mero botón, sino de la mismísima ventana principal. Estoy escribiendo un gestor genérico de ventanas, y necesito interceptar el mensaje &lt;i&gt;WM_ACTIVATEAPP&lt;/i&gt;. Podría obligar al programador que utilice mi gestor a derivar &lt;i&gt;su&lt;/i&gt; ventana principal de una clase base &lt;i&gt;mía&lt;/i&gt;, debidamente retocada. Sería chapucero, no obstante.&lt;/div&gt;&lt;div style="font-size: 90%; margin-left:24px; margin-right:24px; background-color: #c0c0ff; padding: 4px 8px 4px 8px; line-height:105%;"&gt;Este es un problema bastante general del modelo de programación orientada a objetos que terminó imponiéndose en nuestros lenguajes de programación: el tipo de objeto va unido indisolublemente a su entidad. Un coche de turismo no se puede convertir dinámicamente en una ambulancia... aunque en la vida real, los turismos puedan utilizarse así. Este problema hace complicado trabajar con bases de datos orientadas a objetos cuyo modelo de objetos sea parecido al de C++, Java o C#. No me malinterprete: el modelo con tipos estáticos es estupendo para escribir cierto tipo de programas, pero es malo para las bases de datos, en las que un objeto de la clase Contacto puede fácilmente en un Cliente, y no podemos perder las referencias al contacto durante la metamorfosis.&lt;/div&gt;&lt;div&gt;Lo interesante es que existe una solución muy conocida para este problema... en el API de bajo nivel de Windows; si busca &lt;i&gt;window subclassing&lt;/i&gt; encontrará montones de páginas sobre esta técnica. La pregunta es, ¿cómo conseguir lo mismo utilizando Windows Forms?&lt;/div&gt;&lt;div&gt;La respuesta la tiene la clase &lt;i&gt;NativeWindow&lt;/i&gt;, que nos evita tener que usar PInvoke o cosas peores. ¿Hay que interceptar los mensajes que recibe un control? Pues creamos una clase derivada de &lt;i&gt;NativeWindow&lt;/i&gt;, sobrescribimos su método virtual &lt;i&gt;WndProc&lt;/i&gt; y, para asociarla al puñetero botón, usamos el método &lt;i&gt;AssignHandle&lt;/i&gt; de &lt;i&gt;NativeWindow&lt;/i&gt; para copiar en una instancia de la nueva clase el identificador de ventana del botón a vigilar. Los mensajes de ventana que normalmente recibiría el botón serán ahora recibidos también por nuestra instancia de la clase derivada de &lt;i&gt;NativeWindow&lt;/i&gt;.&lt;/div&gt;&lt;div&gt;Es cierto que seguimos necesitando crear una clase por herencia. Si necesitamos realizar esta operación de vigilancia con &lt;i&gt;N&lt;/i&gt; tipos diferentes de botones, ¿significa que tendremos que crear &lt;i&gt;N&lt;/i&gt; clases derivadas de &lt;i&gt;NativeWindow&lt;/i&gt;? Resulta que no: podemos definir una sola clase derivada de &lt;i&gt;NativeWindow&lt;/i&gt; sin tener conocimiento del control concreto que vigilaremos y las acciones concretas que queremos ejecutar. Lo que haríamos en su &lt;i&gt;WndProc&lt;/i&gt;, sencillamente, sería llamar a una variable de tipo &lt;b&gt;delegate&lt;/b&gt; que especificaríamos al crear las instancia de dicha clase. Y sería ese delegado donde implementaríamos el código necesario:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;private sealed class&lt;/b&gt; &lt;font color="darkcyan"&gt;PeepingTom&lt;/font&gt; : &lt;font color="darkcyan"&gt;NativeWindow&lt;/font&gt;, &lt;font color="darkcyan"&gt;IDisposable&lt;/font&gt;&lt;br /&gt;{&lt;br /&gt;  &lt;b&gt;public delegate void&lt;/b&gt; WindowProc(&lt;b&gt;ref&lt;/b&gt; &lt;font color="darkcyan"&gt;Message&lt;/font&gt; m);&lt;br /&gt;&lt;br /&gt;  &lt;b&gt;private&lt;/b&gt; &lt;font color="darkcyan"&gt;WindowProc&lt;/font&gt; tommy;&lt;br /&gt;&lt;br /&gt;  &lt;b&gt;public&lt;/b&gt; PeepingTom(&lt;font color="darkcyan"&gt;Control&lt;/font&gt; ladyGodiva, &lt;font color="darkcyan"&gt;WindowProc&lt;/font&gt; tommy)&lt;br /&gt;  {&lt;br /&gt;    &lt;b&gt;this&lt;/b&gt;.tommy = tommy;&lt;br /&gt;    &lt;b&gt;this&lt;/b&gt;.AssignHandle(ladyGodiva.Handle);&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  &lt;b&gt;public void&lt;/b&gt; Dispose()&lt;br /&gt;  {&lt;br /&gt;    &lt;b&gt;this&lt;/b&gt;.ReleaseHandle();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  &lt;b&gt;protected override void&lt;/b&gt; WndProc(&lt;b&gt;ref&lt;/b&gt; &lt;font color="darkcyan"&gt;Message&lt;/font&gt; m)&lt;br /&gt;  {&lt;br /&gt;    tommy(&lt;b&gt;ref&lt;/b&gt; m);&lt;br /&gt;    &lt;b&gt;base&lt;/b&gt;.WndProc(&lt;b&gt;ref&lt;/b&gt; m);&lt;br /&gt;  }&lt;br /&gt;}&lt;/pre&gt;&lt;div&gt;Los nombres, por supuesto, hacen referencia a la historia de &lt;a href="http://public-domain-images.blogspot.com/2010/06/lady-godiva-by-john-collier.html" target="_blank"&gt;Lady Godiva&lt;/a&gt;, que se paseó desnuda a caballo por todo Coventry para obligar a su marido a bajar los impuestos (¡que no se le ocurra la idea a la Sonsoles, please!), y a un tal Peeping Tom, o Tomasito el Mirón, que desobedeciendo las órdenes del cabreado marido, se escondió para regocijarse con la visión de la damita en pelotas.&lt;/div&gt;&lt;div&gt;Suponga ahora que tenemos un formulario con un botón, y que queremos saber cuándo el ratón pasa por encima del botón. Para asignarle un espía al botón, dado el diseño de nuestra clase, tenemos que esperar al evento &lt;i&gt;Load&lt;/i&gt; del formulario, para asegurarnos de que el identificador de ventana del botón haya sido creado. En ese momento, hacemos algo parecido a esto:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;private void&lt;/b&gt; Form1_Load(&lt;b&gt;object&lt;/b&gt; sender, &lt;font color="darkcyan"&gt;EventArgs&lt;/font&gt; e)&lt;br /&gt;{&lt;br /&gt;  &lt;b&gt;new&lt;/b&gt; &lt;font color="darkcyan"&gt;PeepingTom&lt;/font&gt;(button1,&lt;br /&gt;    &lt;b&gt;delegate&lt;/b&gt;(&lt;b&gt;ref&lt;/b&gt; &lt;font color="darkcyan"&gt;Message&lt;/font&gt; m)&lt;br /&gt;    {&lt;br /&gt;      &lt;b&gt;if&lt;/b&gt; (m.Msg == 0x02A1)&lt;br /&gt;        &lt;b&gt;this&lt;/b&gt;.Text = &lt;font color="maroon"&gt;"Mouse hover"&lt;/font&gt;;&lt;br /&gt;      &lt;b&gt;else if&lt;/b&gt; (m.Msg == 0x02A3)&lt;br /&gt;        &lt;b&gt;this&lt;/b&gt;.Text = &lt;font color="maroon"&gt;"Mouse leave"&lt;/font&gt;;&lt;br /&gt;    });&lt;br /&gt;}&lt;/pre&gt;&lt;div&gt;El ejemplo no es muy bueno, porque para esta tarea en particular, ya tenemos eventos en la clase &lt;i&gt;Button&lt;/i&gt;, pero espero que sirva para que se haga una idea.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-7347546949860864704?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/7347546949860864704/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=7347546949860864704&amp;isPopup=true' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7347546949860864704'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7347546949860864704'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2010/09/como-espiar-los-mensajes-de-un-control.html' title='Cómo espiar los mensajes de un control'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_QWaXq7W8dVI/TIa7P8vEPWI/AAAAAAAAARU/5okcoM8XOco/s72-c/spyingmsgs.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-2581974183772684019</id><published>2010-09-04T17:29:00.008+02:00</published><updated>2010-09-04T19:56:55.045+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='controles'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows Forms'/><title type='text'>Una ventana dentro de otra</title><content type='html'>&lt;div&gt;&lt;img style="float:right; margin:1px 0 1px 8px; border-style:none;" src="http://4.bp.blogspot.com/_QWaXq7W8dVI/TIJoX6l8mKI/AAAAAAAAARM/9sv_8ZATjko/s320/magritte.jpg" border="0" alt="La Condition Humaine, de René Magritte" /&gt;&lt;span class="first"&gt;Este es un truco rápido y&lt;/span&gt; sencillo que, sin embargo, es difícil encontrar a la primera buscando en Internet:&lt;/div&gt;&lt;ul&gt;&lt;li&gt;¿Cómo meter una ventana dentro de otra?&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;¿Y para qué le puede hacer falta tal cosa? Un uso evidente sería crear un sistema de &lt;i&gt;docking&lt;/i&gt;, que permita agrupar dinámicamente varias ventanas dentro de un contenedor; naturalmente, saber cómo meter una ventana independiente dentro de otro control es sólo el comienzo del proceso.&lt;/div&gt;&lt;div&gt;Pero existe otro uso más mundano: imagine que está creando un administrador de ventanas. Teóricamente, el administrador debe permitirle cambiar el estilo de la aplicación a petición del usuario: de ventanas SDI individuales, a una interfaz basada en pestañas e incluso a un sistema MDI. ¿Cómo deberían implementarse las ventanas para que pudiesen utilizarse con este gestor? Una posibilidad, que he utilizado en varios proyectos, es que las "ventanas" se diseñen como controles de usuarios (&lt;i&gt;UserControl&lt;/i&gt;). El motivo es lo fácil que se añade un control dentro de otro, ya sea en tiempo de diseño o de ejecución.&lt;/div&gt;&lt;div&gt;Sin embargo, no es tan evidente cómo meter una instancia de la clase &lt;i&gt;Form&lt;/i&gt; dentro de, digamos, un &lt;i&gt;TabPage&lt;/i&gt;. Si lo intenta, sin más, provocará una excepción advirtiendo que "no se puede meter un control de nivel superior dentro de otro". El error, por fortuna, nos indica también la solución. Hay una propiedad poco conocida de la clase &lt;i&gt;Form&lt;/i&gt;, que hay que poner a &lt;b&gt;false&lt;/b&gt;. Por ejemplo, si queremos meter una instancia de la clase &lt;i&gt;Form2&lt;/i&gt; dentro de una nueva página de un &lt;i&gt;TabControl&lt;/i&gt;, necesitaremos algo parecido a esto:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;var&lt;/b&gt; f2 = &lt;b&gt;new&lt;/b&gt; &lt;font color="darkcyan"&gt;Form2&lt;/font&gt;();&lt;br /&gt;f2.TopLevel = &lt;b&gt;false&lt;/b&gt;;&lt;br /&gt;f2.FormBorderStyle = &lt;font color="darkcyan"&gt;FormBorderStyle&lt;/font&gt;.None;&lt;br /&gt;f2.Dock = &lt;font color="darkcyan"&gt;DockStyle&lt;/font&gt;.Fill;&lt;br /&gt;&lt;b&gt;var&lt;/b&gt; tp = &lt;b&gt;new&lt;/b&gt; &lt;font color="darkcyan"&gt;TabPage&lt;/font&gt;(&lt;br /&gt;  tabControl1.TabPages.Count.ToString());&lt;br /&gt;tabControl1.TabPages.Add(tp);&lt;br /&gt;tp.Controls.Add(f2);&lt;br /&gt;f2.Visible = &lt;b&gt;true&lt;/b&gt;;&lt;/pre&gt;&lt;div&gt;Aquí he metido la ventana, que puede haber sido diseñada al antojo del programador, dentro de un control de pestañas. Pero es igualmente posible meterla directamente dentro de un prototipo vacío de ventana hija MDI... o lo que se le ocurra.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-2581974183772684019?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/2581974183772684019/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=2581974183772684019&amp;isPopup=true' title='11 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2581974183772684019'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2581974183772684019'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2010/09/una-ventana-dentro-de-otra.html' title='Una ventana dentro de otra'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_QWaXq7W8dVI/TIJoX6l8mKI/AAAAAAAAARM/9sv_8ZATjko/s72-c/magritte.jpg' height='72' width='72'/><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-6930180872060961821</id><published>2010-08-22T20:27:00.016+02:00</published><updated>2010-08-22T21:44:07.664+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='EF'/><category scheme='http://www.blogger.com/atom/ns#' term='bases de datos'/><category scheme='http://www.blogger.com/atom/ns#' term='ideas'/><title type='text'>Validación en Entity Framework</title><content type='html'>&lt;h3&gt;Metodologías e ideologías&lt;/h3&gt;&lt;div&gt;&lt;span class="first"&gt;Debo comenzar confesando&lt;/span&gt; que la moda &lt;i&gt;domain-driven&lt;/i&gt; me parece ridícula. Es cierto que la programación orientada a objetos es estupenda… y que el modelo relacional también lo es. También es cierto que, al mezclarlos, se produce un desajuste que en inglés llaman &lt;i&gt;impedance mismatch&lt;/i&gt;. Pero los intentos de "resolver" el problema mediante la metodología &lt;i&gt;domain-driven&lt;/i&gt; consisten, básicamente, en cargarse todas las bondades del modelo relacional, de la arquitectura cliente-servidor y, de paso, la mayoría de los avances aparecidos y probados en estos cuarenta años de bases de datos relacionales.&lt;/div&gt;&lt;div&gt;No es éste el lugar para explicar todo lo que tengo en contra del DD, por lo que me limitaré a un solo argumento. ¿Existe alguna diferencia básica, digamos, entre una aplicación "de negocios" y una aplicación, digamos, como Word o un sistema operativo? Claro que la hay: el dinamismo de las llamadas reglas de negocio. Usted puede escribir una clase para un procesador de texto y atiborrarla de reglas sobre el tratamiento de las mayúsculas. Probablemente, dentro de cinco años esas reglas seguirán siendo igual de malas o apropiadas. En cambio, las reglas para el funcionamiento de una aplicación de negocios cambian constantemente.&lt;img style="float:right; margin:1px 0 1px 8px; border-style:none; padding:0px;" src="http://1.bp.blogspot.com/_QWaXq7W8dVI/THF8MbOEq3I/AAAAAAAAARE/plsXTM3yZsM/s320/carl.jpg" border="0" alt="Este tío cree en el domain-driven..." /&gt; Si usted enchufa esas reglas como parte de métodos de las clases "de negocio", tendrá que contratar a un &lt;i&gt;nerd&lt;/i&gt; granujiento a jornada completa, para que cada vez que el dueño del negocio se cambie los gayumbos, cambie la programación de las clases afectadas, recompile y reinstale el sistema.&lt;/div&gt;&lt;div&gt;Por supuesto, esto es lo que todo &lt;i&gt;nerd&lt;/i&gt; desea: un trabajo fijo a jornada completa, ya sea cambiando detallitos insignificantes de la clase &lt;i&gt;Order&lt;/i&gt; o "tuneando" el núcleo de su instalación personal de Linux, que le deje tiempo para conectarse al Facebook y para jugar a dragones y mazmorras. Es comprensible. Otra cosa es que sea racional o eficiente. O bueno para alguien excepto para el propio &lt;i&gt;nerd&lt;/i&gt;.&lt;/div&gt;&lt;h3&gt;La cabra y el monte&lt;/h3&gt;&lt;div&gt;&lt;img style="float:left; margin:1px 8px 1px 0px;border-style:none;padding:0px;" src="http://2.bp.blogspot.com/_QWaXq7W8dVI/THF644rHyII/AAAAAAAAAQ8/hpmt9UPtm8Q/s320/goat.jpg" border="0" alt="Sí, se parece probablemente a algún compañero de trabajo" /&gt;Las modas, al final, visten a personas reales. Quiero decir, que si al artista se le olvidó la ranura en el pantalón para hacer pis, el portador de la prenda ya se las arreglará para orinar; eso, o reventará. Por mucho &lt;i&gt;domain-driven&lt;/i&gt; que haya infectado la cabecita del pobre programador, en cuanto necesite hierba, la cabra irá al monte… o reventará, ya sabe. ¿Un ejemplo? Teóricamente, en el mundo ideal de nuestros &lt;i&gt;guitar heroes&lt;/i&gt; con acné, cada clase debería ocuparse de su propia validación. Pero, ¡oh, qué penita!, los programadores reales que trabajan con Entity Framework han adquirido la costumbre de acumular validaciones dentro del código del método &lt;i&gt;SaveChanges&lt;/i&gt; (hay varias formas de conseguirlo).&lt;/div&gt;&lt;div&gt;¿Es eso bueno, o malo? Hay de todo. Esperar a &lt;i&gt;SaveChanges&lt;/i&gt; para comprobar que una fecha de nacimiento no pertenece al siglo XII, por ejemplo, es una soberana estupidez. Pero si la regla depende del estado de una entidad, no le queda más remedio que enredar con el administrador del estado: la pureza &lt;i&gt;domain-driven&lt;/i&gt; exige que este estado sea externo a la entidad. Por ese motivo, era tan complicado utilizar entidades con servicios WCF en la versión anterior de .NET. Y por ese motivo, gracias al cielo, Microsoft ha terminado ciscándose en la pureza y regalándonos &lt;i&gt;self-tracking entities&lt;/i&gt; en la nueva versión. Viva lo impuro cuando resuelve problemas.&lt;/div&gt;&lt;div&gt;¿Y qué dice la sacrosanta teoría sobre todo esto? En honor a la verdad, la Programación Orientada a Objetos dice que, en este caso particular, la centralización es mala. Y tiene razón… si se tiene en cuenta el contexto sobre el que se desarrolla esta metodología: un mundo en el que las principales extensiones a una aplicación se producen principalmente mediante la incorporación de nuevas entidades. Pero este no es el escenario característico de una aplicación de ventas, de préstamos o de Bolsa, donde es más probable que aparezcan nuevas reglas para los viejos objetos que nuevos objetos con nuevas reglas. El impacto de la modificación de las nuevas reglas es mayor si el código que las controla está disperso a lo largo y ancho de los ficheros individuales de clases de entidades.&lt;/div&gt;&lt;div&gt;Y hay más: observe que estas reglas de negocio suelen referirse al estado observable de las entidades de negocio. Traducido a código fuente: las reglas de negocio, por lo general, afectan a propiedades públicas de estas clases. Al fin y al cabo, estas reglas son establecidas por analistas funcionales… o por el propio jefe del cotarro; es decir, por gente que no tiene por qué enredarse con &lt;b&gt;protected&lt;/b&gt;, &lt;b&gt;private&lt;/b&gt; e &lt;b&gt;internal&lt;/b&gt;.&lt;/div&gt;&lt;h3&gt;Cabalgando la ola&lt;/h3&gt;&lt;div&gt;La centralización, por lo tanto, no siempre es mala; digamos, entonces, que aceptamos que una parte de las reglas de negocio se implementan como parte del mecanismo de sincronización de los cambios con la base de datos. Sin embargo, ¡seguimos necesitando al &lt;i&gt;nerd&lt;/i&gt;! Para cada cambio en las reglas, sigue siendo necesario recompilar la aplicación… y redistribuirla.&lt;/div&gt;&lt;div&gt;No sólo eso: imagine que su aplicación la utilizan varias empresas. O incluso, que la utiliza una sola empresa, pero que ésta tiene sucursales en distintos países, con diferentes legislaciones e idiosincrasias. Cada vez que en China cambien las reglas de descuentos para sujetadores, en la sucursal de Groenlandia tendrán que reinstalar el maldito software de ventas.&lt;/div&gt;&lt;div&gt;¿Y si movemos esas reglas fuera de la aplicación? Hablo de ubicar las reglas en un fichero de texto, de manera que la aplicación lo lea, digamos que al iniciarse. El contenido del fichero sería traducido a código ejecutable (eso es muy sencillo, con toda la tecnología que ofrece .NET) que se ejecutaría como parte del método &lt;i&gt;SaveChanges&lt;/i&gt; del contexto.&lt;/div&gt;&lt;div&gt;Será más sencillo si muestro un ejemplo de reglas. La sintaxis concreta que he utilizado imita a la de C#, pero está claro que las variaciones son posibles:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;class&lt;/b&gt; Order&lt;br /&gt;{&lt;br /&gt;  &lt;b&gt;on insert&lt;/b&gt;&lt;br /&gt;    Created = DateTime.Now;&lt;br /&gt;  &lt;b&gt;on update&lt;/b&gt;&lt;br /&gt;    Modified = DateTime.Now;&lt;br /&gt;  &lt;b&gt;rule&lt;/b&gt; MustPaidBeforeShipping &lt;b&gt;is&lt;/b&gt;&lt;br /&gt;    Paid || !ShipDate.HasValue;&lt;br /&gt;}&lt;/pre&gt;&lt;div&gt;La explicación:&lt;/div&gt;&lt;ol&gt;&lt;li&gt;Las reglas se definen por clase. Esto es así por la forma en la que puede tener lugar la validación durante &lt;i&gt;OnSavingChanges&lt;/i&gt;: el componente que ejecuta el script recorrerá los &lt;i&gt;ObjectStateEntry&lt;/i&gt; modificados en el contexto. Para cada uno de ellos, se elegirá el conjunto de reglas a ejecutar o verificar de acuerdo al tipo de entidad asociado, y luego, al estado de la entidad.&lt;/li&gt;&lt;li&gt;Es recomendable que se respete la herencia. Si una regla se define en una clase base, debe respetarse también en las posibles clases derivadas, siempre que una de estas no la anule.&lt;/li&gt;&lt;li&gt;Como mínimo, se deben soportar dos tipos de reglas: verificaciones y asignaciones a propiedades. En el ejemplo, hay dos asignaciones a propiedades, separadas según el estado de la entidad, y una sola verificación, que al no mencionar el estado, se activará tanto para inserciones como para actualizaciones.&lt;/li&gt;&lt;li&gt;Cada regla tiene un identificador asociado. El escenario típico de estas validaciones será un proceso WCF remoto. Imagine que asociamos un mensaje de error directamente con la regla: ¿en qué idioma debería estar? Un servicio de capa intermedia debe evitar atarse a un idioma concreto, porque puede estar siendo utilizado por clientes configurados para idiomas diferentes. De todos modos, debería ser posible sustituir el identificador por un literal de cadena, para casos sencillos en que no se prevé la traducción a otros idiomas.&lt;/li&gt;&lt;li&gt;Las expresiones trabajarían, principalmente, sobre entidades aisladas, por lo que no habría que preocuparse por extensiones del tipo LINQ: si usted quiere verificar que el total de una orden no sea superior a un valor, por ejemplo, prográmelo &lt;b&gt;donde realmente corresponde&lt;/b&gt;, es decir, en la base de datos. Entity Framework no le puede ofrecer garantías, llegados a este punto, de que el grafo de entidades asociados a la entidad modificada, esté completamente cargado en memoria. Sólo piense, por ejemplo, lo difícil que es verificar la unicidad de una columna en un proceso cliente, sin tener todas las entidades en memoria y sin lanzar una consulta adicional al servidor.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;Sobre las expresiones soportadas: en principio, no haría falta complicarlas con índices y corchetes, por las razones antes expuestas. Las expresiones básicas serían constantes y "rutas de objetos" (&lt;i&gt;object paths&lt;/i&gt;). Estas rutas siempre comenzarían por una propiedad de la clase que define la regla, o por una clase o espacio de nombres. En nuestro ejemplo, &lt;i&gt;ShipDate.HasValue&lt;/i&gt; comienza por una propiedad de la clase &lt;i&gt;Order&lt;/i&gt;, pero &lt;i&gt;DateTime.Now&lt;/i&gt; es, evidentemente, una propiedad estática de una conocida clase. Este tipo de sintaxis es muy fácil de implementar y traducir.&lt;/div&gt;&lt;div&gt;Las expresiones, que son el núcleo de nuestro sistema, se traducirían como árboles de expresiones LINQ, que se pueden compilar a código nativo dinámicamente. En esto ya tengo también bastante experiencia: el sistema es sencillo y muy eficiente (lo he utilizado en filtros a la medida para un servidor RTD para Excel, implementado dentro de una aplicación de servicios de Windows).&lt;/div&gt;&lt;h3&gt;En resumen&lt;/h3&gt;&lt;div&gt;Se trata solamente, en esta etapa, de una propuesta: crear un componente que, a partir de un script externo, se ocupe de determinadas validaciones e inicializaciones dentro del Entity Framework. Es fácil señalar el método &lt;i&gt;SaveChanges&lt;/i&gt; como el punto donde se insertaría el componente de validación. Probablemente existan más puntos donde se pueda actuar.&lt;/div&gt;&lt;div&gt;En principio, el script con las reglas puede estar ubicado en un fichero de texto. Esto sería apropiado si las aplicaciones clientes accediesen a las entidades a través de un servicio WCF. Sería este servicio quien centralizaría el manejo del script y determinaría las reglas a cumplir. Pero sería sencillo extender el mecanismo, en ausencia de una capa intermedia, ubicando las reglas en la base de datos, para simplificar el cambio de las mismas.&lt;/div&gt;&lt;div&gt;Por supuesto, escribo esto, en este momento, para recabar sugerencias.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-6930180872060961821?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/6930180872060961821/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=6930180872060961821&amp;isPopup=true' title='21 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/6930180872060961821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/6930180872060961821'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2010/08/validacion-en-entity-framework.html' title='Validación en Entity Framework'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_QWaXq7W8dVI/THF8MbOEq3I/AAAAAAAAARE/plsXTM3yZsM/s72-c/carl.jpg' height='72' width='72'/><thr:total>21</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-2429779170278466545</id><published>2010-06-02T16:01:00.001+02:00</published><updated>2010-06-02T16:02:22.250+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='yo'/><title type='text'>Música para piano</title><content type='html'>&lt;div&gt;... pues eso: &lt;a href="http://www.marteens.com/media/topsham.mp3"&gt;música para piano&lt;/a&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-2429779170278466545?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/2429779170278466545/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=2429779170278466545&amp;isPopup=true' title='7 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2429779170278466545'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2429779170278466545'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2010/06/musica-para-piano.html' title='Música para piano'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-2316491907360551083</id><published>2010-03-29T16:35:00.003+02:00</published><updated>2010-03-29T16:41:28.029+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='trabajo'/><title type='text'>Trabajo en Delphi</title><content type='html'>&lt;div style="border: 1px solid #0c0c0f; padding: 8px; text-align: center; background-color: #f0f0f0;"&gt;Se busca programador en lenguaje Delphi, abstenerse freelance, se valoraran conocimientos en base de datos SQL. Imprescindible Delphi.&lt;br /&gt;Empresa situada en Madrid. Enviar curriculum  a &lt;a href="mailto:wis@worldwis.es"&gt;wis@worldwis.es&lt;/a&gt;.&lt;/div&gt;&lt;div style="font-style: italic; font-size: 85%;"&gt;(... y sí: dentro de poco habrá noticias sobre nuevos cursos de C#, y gracias a Marcos Santín, de Delphi, y más...)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-2316491907360551083?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/2316491907360551083/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=2316491907360551083&amp;isPopup=true' title='6 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2316491907360551083'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2316491907360551083'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2010/03/trabajo-en-delphi.html' title='Trabajo en Delphi'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-5849288498365483524</id><published>2009-07-24T14:39:00.019+02:00</published><updated>2009-07-24T16:10:34.711+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='disparates'/><category scheme='http://www.blogger.com/atom/ns#' term='metodología'/><title type='text'>Cagarse en el chocolate</title><content type='html'>&lt;h3&gt;Serie: Los N Pecados Capitales&lt;/h3&gt;&lt;div&gt;&lt;img style="float:right; margin:1px 0 1px 8px;border-style:none;padding:0px;" src="http://3.bp.blogspot.com/_QWaXq7W8dVI/Smm2R-QgmBI/AAAAAAAAAQs/irC73PA9QH8/s400/oompaloompasqueenbee.jpg" border="0" alt="Scott McNealy: Zángano Padre de todos los Oompa Loompas de este mundo" /&gt;&lt;span class="first"&gt;En la empresa de Willy&lt;/span&gt; Wonka, se fabrica un exquisito chocolate. Al menos, esa es la opinión general. La producción está a cargo de los umpalumpas: una extraña raza de friquis canijos, adictos a la programación en Java, a los que pagan con granos de cacao.&lt;/div&gt;&lt;div&gt;Los umpalumpas tienen la curiosa manía de inventarse canciones sobre la marcha, y luego pretender que se trata de tonadas tradicionales, de las de toda la vida. Por ejemplo, si un niño glotón se cae dentro del río de chocolate, improvisan una canción explicando por qué no se debe uno inclinar demasiado sobre la corriente. Si un proyecto de desarrollo fracasa estrepitosamente, se inventan melodías que hacen referencia a dominios escuálidos, programación ágil e inversión del control. Son pintorescos, estos personajillos.&lt;/div&gt;&lt;div&gt;Pero los umpalumpas tienen también una costumbre muy fea. Alex, un umpalumpa de Pontevedra, revuelve el chocolate fundido cuando siente que algo más se revuelve en su interior:&lt;/div&gt;&lt;div style="margin-left: 24px; margin-right:24px;"&gt;- Willy… ehm… señor Wonka.&lt;br /&gt;- ¿Sí, Alex?&lt;br /&gt;- Tengo un apretonciño de intestinos…&lt;br /&gt;- Te aguantas. Esta barra de chocolate tenía que estar para ayer.&lt;br /&gt;- ¡Pero es que me lo voy a hacer encima!&lt;br /&gt;- Caga entonces dentro de la tina del chocolate.&lt;br /&gt;- ¡¿Cómo?!&lt;br /&gt;- Joder, Alejandrito, ¿tengo que dibujarte un diagrama de clases?&lt;br /&gt;- Pero, ¿cómo vamos a echar mierda dentro del chocolate?&lt;br /&gt;- A ver, ¿de qué color es el chocolate? Marrón. ¿Y la mierda? Marrón. Un poco de mierda espesa aporta crema al cacao.&lt;br /&gt;- Pero… es que estoy un poco estreñido y estoy cagando boliñas, como las de las cabras…&lt;br /&gt;- Pues mejor aún: chocolate con cacahuetes, y si las bolas son más grandes, con nueces y avellanas.&lt;/div&gt;&lt;div&gt;Por desgracia, la mierda de umpalumpa es sumamente corrosiva. Por su culpa, caen aviones, revientan naves espaciales, fallan sistemas de soporte vital en hospitales y se aplican dosis excesivas de radiación a pacientes de radioterapia. Será mierda, pero hay que tomársela muy en serio.&lt;/div&gt;&lt;div&gt;Hay mil y una maneras de cagarse en el chocolate. Por mencionar unas pocas:&lt;/div&gt;&lt;ol&gt;&lt;li&gt;Una aplicación para almacenar expedientes médicos, escrita en dBase, generaba claves primarias mediante el sucio mecanismo de contar los registros en el fichero y aumentar el valor en uno. Mientras el hospital tuvo un único ordenador en admisión, el chocolate sabía a ambrosía. Un día instalaron un segundo ordenador, y en algún momento, se crearon dos registros simultáneamente… con la misma clave primaria. Migrando la aplicación a InterBase, en el 2000, alguien tropezó con la historia clínica de un buen señor que había sufrido la extirpación de sus ovarios.&lt;/li&gt;&lt;li&gt;En la historia anterior, el error no se detectó porque los índices de aquella versión de dBase no permitían la comprobación de unicidad. Pero conozco un par de sistema implementados sobre Oracle en los que los “diseñadores” (es un decir) han evitado el uso de claves primarias concienzudamente.&lt;/li&gt;&lt;li&gt;La mismísima Borland se cagó, en su momento, en el chocolate de la casa. Cuando apareció Delphi 2, se produjo una ola de fallos en aplicaciones de servidor. La causa: en servidores con procesadores Xeon, fallaban determinadas operaciones sobre cadenas de caracteres, porque la implementación del tipo &lt;i&gt;String&lt;/i&gt; no era &lt;i&gt;thread-safe&lt;/i&gt;.&lt;/li&gt;&lt;li&gt;Todos sabemos, o eso espero, que no debemos acceder a los métodos de un objeto de ventana desde un hilo diferente a aquel en el que fue creada. Sin embargo, este tipo de violación no es verificada en ningún caso por .NET Framework v1.1. Muchas aplicaciones, por lo tanto, ignoran total o parcialmente el problema… hasta que migran a una versión más reciente de la plataforma y empiezan a reventar por todas partes. Entonces, improvisan cantando los umpalumpas, la culpa es de Microsoft, evidentemente.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;¿Se ha dado cuenta ya de cuál es el patrón emergente? Se trata siempre de fallos que se producen al no tener en cuenta la concurrencia. La técnica ingenua de generación de claves primarias funciona mientras hay un solo ordenador. La implementación defectuosa de las operaciones de cadenas funciona incluso cuando hay varios hilos, pero siempre que exista un único núcleo. Los errores de reentrancia de Windows Forms y WPF se producen pero no se notan… hasta que el sistema revienta por causas desconocidas.&lt;/div&gt;&lt;div&gt;Cuando se trabaja con una base de datos relacional, además, en teoría existe una forma muy sencilla de evitar la mayoría de los errores: trabaje con transacciones serializables. ¡Pero la mayoría de los programadores, o desconocen su existencia, o tienen miedo a la pérdida de velocidad! De hecho, la mayoría de las operaciones complejas en las bases de datos habituales pueden implementarse con un nivel de aislamiento más bajo, si se ordenan inteligentemente las instrucciones. Esto es algo, sin embargo, que se encuentra fuera del alcance de la mayoría. Y quien sospecha que hay algo que puede fallar en su implementación, termina cagando dentro del chocolate: ya haremos algo cuando falle.&lt;/div&gt;&lt;div&gt;Otra fuente habitual de tropezones en el cacao: los errores de redondeo. ¿Cuántos programadores, de los que trabajan con aplicaciones financieras, tienen idea sobre los problemas de estabilidad numérica y sus consecuencias en el desarrollo? Es más fácil tener una idea vaga de que existe un problema "teórico", y dejar que sea el desdichado usuario el que hunda sus dientes en la mierda de umpalumpa. Sólo entonces merece la pena hacer algo.&lt;/div&gt;&lt;div&gt;¿Existe alguna solución mágica para evitar sustancias extrañas en nuestros alimentos? Por desgracia, sólo hay una forma, y requiere una cualidad personal muy extraña y poco valorada: la ética profesional. Pero estamos en crisis, y la ética es un bien caro y escaso. Al menos, deberíamos presionar a las autoridades europeas para que los productos de software lleven una etiqueta de advertencia, como las de los sándwiches que venden en las gasolineras:&lt;/div&gt;&lt;div style="margin-left:24px;margin-right:24px;font-style:italic;text-align: center;"&gt;"Puede contener trazas de cacahuetes, pescado, huevo, gluten&lt;br /&gt;y mierda de umpalumpa."&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-5849288498365483524?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/5849288498365483524/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=5849288498365483524&amp;isPopup=true' title='37 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/5849288498365483524'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/5849288498365483524'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2009/07/cagarse-en-el-chocolate.html' title='Cagarse en el chocolate'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_QWaXq7W8dVI/Smm2R-QgmBI/AAAAAAAAAQs/irC73PA9QH8/s72-c/oompaloompasqueenbee.jpg' height='72' width='72'/><thr:total>37</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-2845538779425573987</id><published>2009-07-22T11:08:00.002+02:00</published><updated>2009-07-22T11:10:24.312+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='libros'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><title type='text'>Libro sobre Delphi Prism</title><content type='html'>&lt;a href="http://www.markdelphi.oamm.info/?p=79"&gt;Nuevo libro sobre Delphi Prism&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Ahora tengo prisa (reunión con cliente), pero luego editaré el post, e incluiré fotos y ampliaré el texto. ¡Libro recomendado, por supuesto!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-2845538779425573987?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/2845538779425573987/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=2845538779425573987&amp;isPopup=true' title='24 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2845538779425573987'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2845538779425573987'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2009/07/libro-sobre-delphi-prism.html' title='Libro sobre Delphi Prism'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>24</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-8690069406098852174</id><published>2009-07-20T20:36:00.003+02:00</published><updated>2009-07-20T20:42:44.371+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ideas'/><title type='text'>El Bien y el Mal</title><content type='html'>&lt;i&gt;Lo único necesario para que el Mal triunfe, es que los hombres buenos no hagan nada.&lt;/i&gt;&lt;br /&gt;(cita atribuida, erróneamente, a Edmund Burke, pero que no por ello es menos cierta)&lt;br /&gt;(y no, no tiene nada que ver con la Informática)&lt;br /&gt;&lt;hr&gt;&lt;br /&gt;&lt;div&gt;Me descuido un poco... y veo que se me acumulan 211 comentarios en el último post. Eso es bueno, por supuesto: muchas gracias. Siento no haber estado disponible: estoy con el libro, el curso de EF y un software a entregar para ayer.&lt;/div&gt;&lt;div&gt;Y ahora pregunto yo: ¿sería buena idea si montásemos un foro? Principalmente para soporte y esas cosas. Me comprometo a entrar regularmente. Y tendría que haber una carpeta para "off-topics", que si no, sería demasiado aburrido. Tengo que preguntar primero a los que alojan mi página (los buenos amigos de la Delphi Magazine) sobre softwares compatibles con sus servidores, por supuesto...&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-8690069406098852174?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/8690069406098852174/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=8690069406098852174&amp;isPopup=true' title='11 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/8690069406098852174'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/8690069406098852174'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2009/07/el-bien-y-el-mal.html' title='El Bien y el Mal'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-2571116406537632833</id><published>2009-04-15T16:04:00.006+02:00</published><updated>2009-04-15T20:11:11.092+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='libros'/><category scheme='http://www.blogger.com/atom/ns#' term='EF'/><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>Una decepción y un rayo de esperanza</title><content type='html'>&lt;h3&gt;La decepción&lt;/h3&gt;&lt;div&gt;&lt;span class="first"&gt;Apartaos de este libro&lt;/span&gt; cuanto podáis: &lt;a href="http://www.amazon.com/gp/product/0321564162?ie=UTF8&amp;tag=callindrmarte-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=0321564162"&gt;Essential LINQ (Microsoft .NET Development Series)&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=callindrmarte-20&amp;l=as2&amp;o=1&amp;a=0321564162" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;. Ni se me ocurriría comprar un libro de Calvert (ya he tenido la mala experiencia), pero pensé que al estar Dinesh Kulkarni en el potaje, la cosa cambiaría. ¡Qué error!:&lt;/div&gt;&lt;ul type="disc"&gt;&lt;li&gt;Las dos terceras partes del libro son las típicas obviedades sobre LINQ for Objects que puede encontrar en &lt;a href="http://www.marteens.com/pdfs/csharp_intsight.pdf" target="_blank" title="Libro en PDF sobre C#"&gt;Intuitive C#&lt;/a&gt; gratuitamente, o en &lt;a href="http://www.marteens.com/forms/linqform.htm"&gt;el libro de Octavio sobre LINQ&lt;/a&gt; por una fracción del precio. Es el tipo de énfasis que hace un autor que odia las bases de datos y sólo le interesa hacer trinos y gorgoritos con el lenguaje.&lt;/li&gt;&lt;li&gt;El contenido sobre LINQ to SQL (un sistema ya condenado) es el doble o el triple (me niego a contar páginas) que el contenido sobre el Entity Framework.&lt;/li&gt;&lt;li&gt;... pero ni siquiera el contenido sobre LINQ to SQL es medianamente funcional, así que ya puede imaginar lo que hay sobre el EF.&lt;/li&gt;&lt;li&gt;Charlie Calvert nos obsequia con sus mañas características de escritor: apéndices sobre todo lo humano y divino (para engordar el libro y encarecerlo), incluyendo una tabla de seis páginas sobre los atajos de teclados en Visual Studio 2008 (que usted puede encontrar perfectamente en la ayuda de VS).&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;El rayo de esperanza&lt;/h3&gt;&lt;div&gt;&lt;iframe src="http://rcm.amazon.com/e/cm?t=callindrmarte-20&amp;o=1&amp;p=8&amp;l=as1&amp;asins=059652028X&amp;fc1=000000&amp;IS2=1&amp;lt1=_blank&amp;m=amazon&amp;lc1=0000FF&amp;bc1=000000&amp;bg1=FFFFFF&amp;f=ifr&amp;nou=1" style="width:120px;height:240px; float: left; margin: 1px 8px 1px 0;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt;&lt;span&gt;Este otro libro&lt;/span&gt;, &lt;a href="http://www.amazon.com/gp/product/059652028X?ie=UTF8&amp;tag=callindrmarte-20&amp;linkCode=as2&amp;camp=1789&amp;creative=9325&amp;creativeASIN=059652028X"&gt;Programming Entity Framework&lt;/a&gt;&lt;img src="http://www.assoc-amazon.com/e/ir?t=callindrmarte-20&amp;l=as2&amp;o=1&amp;a=059652028X" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /&gt;, de Julia Lerman, es harina de otro costal. Para empezar, tiene 792 páginas con un tipo de letra legible, pero compacto. Nada de trucos sucios para engordar artificialmente el contenido.&lt;/div&gt;&lt;div&gt;En segundo lugar, se tratan todos los temas necesarios: ESQL, los puñeteros formatos de bajo nivel para crear un esquema conceptual y mapearlo a una base de datos, el uso avanzado de procedimientos almacenados, los problemas actuales al intentar trabajar en múltiples capas (¡sinceridad, por una vez en la vida!), cómo usar EF desde ASP.NET y Windows Forms, y los problemas y soluciones en cada plataforma...&lt;/div&gt;&lt;div&gt;Además, y esto es muy importante, la autora escribe bien. No he terminado el libro, y me va a llevar un par de semanas, pero hasta donde he llegado, me siento satisfecho.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-2571116406537632833?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/2571116406537632833/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=2571116406537632833&amp;isPopup=true' title='211 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2571116406537632833'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2571116406537632833'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2009/04/una-decepcion-y-un-rayo-de-esperanza.html' title='Una decepción y un rayo de esperanza'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>211</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-4399174376310704235</id><published>2009-04-04T15:39:00.023+02:00</published><updated>2009-04-04T22:27:49.319+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='metodología'/><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>Perestroika</title><content type='html'>&lt;div&gt;&lt;img style="float:right; margin:1px 0 1px 8px; border-style:none;padding:0px;" src="http://1.bp.blogspot.com/_QWaXq7W8dVI/Sdd2lhON8II/AAAAAAAAAQc/VT5IdR65BSM/s400/marxismfowlerism.jpg" border="0" alt="¡Gloria eterna al marxismo-fowlerismo!" /&gt;&lt;span class="first"&gt;El funcionario de la calva&lt;/span&gt; brillante con la mancha como un mapamundi se levantó y se dirigió hacia los micrófonos. Carraspeó y comenzó a hablar cansinamente, como hablaban los funcionarios de la extinta Unión Soviética:&lt;/div&gt;&lt;div style="margin-left: 24px;"&gt;- &lt;i&gt;Daraguíe tavarischi&lt;/i&gt; - es decir, "hola, troncos" - El Soviet Supremo me ha encargado la honrosa tarea de comunicaros dos noticias. Una buena y una mala. La buena es que hoy ya es viernes.&lt;/div&gt;&lt;div&gt;Un murmullo de satisfacción teñida de falsa sorpresa recorrió la sala.&lt;/div&gt;&lt;div style="margin-left: 24px;"&gt;- La mala - titubeó, aunque sólo un momento - la mala es que lo nuestro no funciona.&lt;/div&gt;&lt;div&gt;Los ecos del murmullo cesaron abruptamente.&lt;/div&gt;&lt;div style="margin-left: 24px;"&gt;- ... y no me refiero a lo de enfriar en una nevera las semillas de patata antes de sembrarlas, para aclimatarlas al frío - el anciano hijo de &lt;a href="http://en.wikipedia.org/wiki/Trofim_Lysenko" target="_blank"&gt;Trofim Lysenko&lt;/a&gt; se levantó airado y abandonó la asamblea - sino a este invento del comunismo.&lt;/div&gt;&lt;div&gt;Una mosca atravesó la enorme sala zumbando. Nadie la detuvo.&lt;/div&gt;&lt;div style="margin-left: 24px;"&gt;- Sí, coño, hemos estado haciendo el panoli durante setenta años. Y para nada. Hemos matado de hambre a media Ucrania. Hemos jodido a conciencia a polacos, húngaros y checos, y a buena parte de Alemania. ¿Y todo para qué? Para que nuestros obreros pasen hambre y frío, para fabricar estos horribles coches y esos espantosos sintetizadores alemanes democráticos que se funden antes de terminar la primera estrofa de la Kalinka. Esto, &lt;i&gt;maí vesyolye rebyata&lt;/i&gt;, no firula...&lt;/div&gt;&lt;div&gt;Los murmullos se reanudaron. El delegado de Dirkadirkastán alzó tímidamente la mano y preguntó:&lt;/div&gt;&lt;div style="margin-left: 24px;"&gt;- Y ahora, ¿qué?&lt;br /&gt;- Ahora - el calvo hizo una pausa teatral - ahora... ¡perestroika!&lt;/div&gt;&lt;hr class="p"&gt;&lt;div&gt;&lt;span class="first"&gt;En Redmond parecen&lt;/span&gt; estar también algo revueltos y perestroikos:&lt;/div&gt;&lt;ul type="square"&gt;&lt;li&gt;&lt;a href="http://blogs.msdn.com/efdesign/archive/2009/03/24/self-tracking-entities-in-the-entity-framework.aspx" target="_blank"&gt;Self-tracking entities in the Entity Framework&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Y ya era hora, coño. Ya era hora de que alguien se diese cuenta de que todo este invento del &lt;a href="http://en.wikipedia.org/wiki/POJO" target="_blank"&gt;POJO&lt;/a&gt;, del POCO y del MOJO POCO no funciona cuando se trata de escribir aplicaciones multicapas. La vanguardia del proletariado, por supuesto, pondrá el grito en el cielo, pero de momento andan callados. Puede que no hayan comprendido lo que hay en juego. En realidad, los fundamentalistas javalinos suelen comprender muy pocas cosas.&lt;/div&gt;&lt;div&gt;Es verdad que los de Microsoft se asemejan más a los chinos que a los rusos: cada cierto tiempo se inventan una Revolución Cultural y no son muy ortodoxos en lo tocante al martinismo-fowlerismo. Además, acaban de perder al Gran Timonel. Y tienen una misma palabra para &lt;i&gt;crisis&lt;/i&gt; y &lt;i&gt;oportunidad&lt;/i&gt;: suena parecido a &lt;i&gt;crisistunidad&lt;/i&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-4399174376310704235?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/4399174376310704235/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=4399174376310704235&amp;isPopup=true' title='84 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/4399174376310704235'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/4399174376310704235'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2009/04/perestroika.html' title='Perestroika'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_QWaXq7W8dVI/Sdd2lhON8II/AAAAAAAAAQc/VT5IdR65BSM/s72-c/marxismfowlerism.jpg' height='72' width='72'/><thr:total>84</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-7092603804214633328</id><published>2009-03-06T22:16:00.002+01:00</published><updated>2009-03-06T22:19:33.866+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='yo'/><title type='text'>Mientras tanto...</title><content type='html'>&lt;div&gt;&lt;span class="first"&gt;... y porque no solo&lt;/span&gt; de pan vive el hombre, un poco de rock instrumental, hecho en casa:&lt;/div&gt;&lt;ul type="square"&gt;&lt;li&gt;&lt;a href="http://www.marteens.com/media/everydayshero.mp3"&gt;Everyday Hero&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Dedicado a todos los que tienen que enfrentarse día a día con su correspondiente Mr. Butters.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-7092603804214633328?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/7092603804214633328/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=7092603804214633328&amp;isPopup=true' title='11 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7092603804214633328'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7092603804214633328'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2009/03/mientras-tanto.html' title='Mientras tanto...'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-2420672051589034496</id><published>2009-03-02T18:53:00.010+01:00</published><updated>2009-03-03T07:39:44.432+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Mr. Butters'/><title type='text'>Mr. Butters (I)</title><content type='html'>&lt;div&gt;&lt;span class="first"&gt;Mr. Butters es un&lt;/span&gt; "experto" imaginario, que trabaja en una empresa imaginaria, y que "controla mogollón" sobre bases de datos, aunque la única base de datos con la que ha trabajado en su puñetera vida es Oracle 9, utilizando sólo los trucos que aprendió para Oracle 7. Es un tipo que desconfía de las &lt;i&gt;foreign keys&lt;/i&gt;, que considera peligrosos los &lt;i&gt;triggers&lt;/i&gt; y los procedimientos almacenados, y que prefiere que el acceso a datos se haga con ODBC... sobre todo por compatibilidad, coño, que somos una empresa seria.&lt;/div&gt;&lt;img style="DISPLAY: block; MARGIN: 1px auto 10px; WIDTH: 480px; padding:0px; border-style:none; TEXT-ALIGN: center" alt="Mr. Butters, Database Expert, Lucky You!" src="http://www.marteens.com/blogs/mrbutters1.jpg" border="0" /&gt;&lt;div&gt;Mr. Butters, por supuesto, es sólo un producto de mi febril imaginación. Cualquier coincidencia con la realidad, es un mero resbalón de mis neuronas.&lt;/div&gt;&lt;div style="font-style:italic;font-size:90%;line-height:normal; margin-left: 24px;"&gt;&lt;span style="font-style: normal; font-weight: bold;"&gt;The Waste Brain&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Mr. Butters is the silliest dork, breeding&lt;br /&gt;Incompetence out from the dead land, mixing&lt;br /&gt;Idiocy and arrogance, stirring&lt;br /&gt;Foolishness with an amazing lack of common sense.&lt;br /&gt;&lt;br /&gt;Visual Basic kept us warm, covering&lt;br /&gt;Bugs in forgetful snow, feeding...&lt;br /&gt;(etc, etc)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-2420672051589034496?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/2420672051589034496/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=2420672051589034496&amp;isPopup=true' title='47 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2420672051589034496'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2420672051589034496'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2009/03/mr-butters-i.html' title='Mr. Butters (I)'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>47</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-4185871902598363102</id><published>2009-02-28T18:01:00.004+01:00</published><updated>2009-02-28T18:33:03.688+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XSight'/><title type='text'>Ajedrez</title><content type='html'>&lt;a href="http://www.marteens.com/xsight/images/chess800.png" target="_blank"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;" src="http://1.bp.blogspot.com/_QWaXq7W8dVI/SaluBAVJWUI/AAAAAAAAAQE/MtXcr7_7iEc/s320/chess320.png" border="0" alt="Hyperbolic surfaces, ambient occlusion, diffuse reflections, area lights, focal blur" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-4185871902598363102?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/4185871902598363102/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=4185871902598363102&amp;isPopup=true' title='7 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/4185871902598363102'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/4185871902598363102'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2009/02/ajedrez.html' title='Ajedrez'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_QWaXq7W8dVI/SaluBAVJWUI/AAAAAAAAAQE/MtXcr7_7iEc/s72-c/chess320.png' height='72' width='72'/><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-2533708553819695816</id><published>2009-02-18T00:24:00.012+01:00</published><updated>2009-02-18T15:41:33.604+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='libros'/><category scheme='http://www.blogger.com/atom/ns#' term='disparates'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>Otra seta, perdón, libro sobre LINQ</title><content type='html'>&lt;div&gt;&lt;iframe src="http://rcm.amazon.com/e/cm?t=callindrmarte-20&amp;o=1&amp;p=8&amp;l=as1&amp;asins=1590599659&amp;fc1=000000&amp;IS2=1&amp;lt1=_blank&amp;m=amazon&amp;lc1=0000FF&amp;bc1=000000&amp;bg1=FFFFFF&amp;f=ifr" style="float: left; width:120px;height:240px; margin: 1px 8px 1px 0;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt;&lt;span class="first"&gt;Cuando comparo este libro&lt;/span&gt; con una seta (y la seta sale ganando al final) no es sólo por la capacidad de propagación por esporas de los libros sobre LINQ sino, principalmente, por su potencial alucinógeno. Leo un par de páginas y alucino. Luego viene la resaca. Pasa un par de horas y siento el mono de volver a comprobar cuán malo es el libro. Y así, entre risas y risas, me lo he leído. Pero las setas tienen fibra y son buenas para el colon.&lt;/div&gt;&lt;div&gt;Vale, me he pasado. Si a usted le cuesta leer en pantalla, este libro puede sustituir a la ayuda en línea, siempre que renuncie al índice, a las búsquedas y a ese estilo seco de los documentos de Microsoft que tanto gusta a los amantes del dolor. De todos modos, supongo que tengo que justificarme. Ahí va eso...&lt;/div&gt;&lt;div&gt;El principal problema de (joder, qué pedazo de título)... bueno, de este título, es la bisoñez del autor, acompañada de un exceso de entusiasmo, buenrrollismo y grandes dosis de soberbia injustificada. Este es un libro de apenas 380 páginas, con los típicos listados sin abreviar y con un tipo de letra más grande que la del texto. A pesar de todo esto, el autor se permite escribir un ditirambo de cuarenta páginas en honor a los ORM... demostrando de paso que no tiene ni pajolera idea del asunto. Ahí va un sabroso "tip" (página 5):&lt;/div&gt;&lt;div style="background-color: #f0f0ff; padding: 4px 8px 4px 8px; font-size: 90%;line-height:105%;"&gt;&lt;b&gt;Note&lt;/b&gt;: Writing stored procedures does not equate to bad design. On the contrary, stored procedures if managed correctly are an excellent alternative to dynamic SQL. If you use a code generator to create your CRUD stored procedures, or if you develop them by hand and have good oversight, in many cases you will be able to use them in conjunction with an ORM tool.&lt;/div&gt;&lt;div&gt;¡Gracias, gran Vijay (así se llama el pavo), por perdonar nuestras viles existencias! Pero siento interrumpir: usted, ¿ha entendido algo? ¿Son buenos o no los procedimientos almacenados? ¿Sólo si se escriben a mano, o si los crea una herramienta? Ah, ¿en ambos casos? Entonces, ¿para qué mencionar que mañana lloverá o no? El problema está en que el Gran Vijay "sabe" que los procedimientos almacenados sólo son buenos si sirven a los propósitos del Gran ORM. Pero soltar tal chorrada es peligroso. Te puede enemistar con esa bestia cejijunta del DBA (en cristiano, el Administrador de Bases de Datos). Los DBA's, cuando se enfadan, te dejan sin índices secundarios y te echan sal en el café.&lt;/div&gt;&lt;div&gt;"Claro, Marteens, cabronazo, pero nos has ocultado el contexto de la parida". Bien aquí tiene el contexto: el señor Mehta nos explica que la compañía X ha escrito software para un fabricante de comida para perros. ¿Y sabe qué?, pues que usaron procedimientos almacenados. La cosa se les escapa de las manos (claro, porque son unos pecadores relacionales). Y de repente, llega la gran oportunidad: pueden vender la aplicación a un fabricante de comida para gatos. Aquí viene la Segunda Parida:&lt;/div&gt;&lt;div style="background-color: #f0f0ff; padding: 4px 8px 4px 8px; font-size: 90%;line-height:105%;"&gt;With the increased development costs, Company X won't be making enough money to justify this deal [...] so they hire a consulting company to help reduce their overhead.&lt;/div&gt;&lt;div&gt;Vijay, hermanito, que nunca se te ocurra montar una empresa con los ahorros de papá, que te los vas a fundir. La consultoría, evidentemente, les endiña un ORM a la Compañía X, y según palabrita del niño Vijay, &lt;i&gt;(they) optimize and normalize the company database&lt;/i&gt;. Lamento señalar que:&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Lo de "optimizar y normalizar" suele resultar bastante costoso. Es como empezar de cero. Para que resulte viable, es obligatorio que la consultoría subcontrate programadores en algún país remoto del Tercer Mundo. Quizás los tiros vayan por ahí.&lt;/li&gt;&lt;li&gt;Ah, de repente la base de datos carece de "normalización". ¿Esa es una consecuencia de utilizar procedimientos almacenados?&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Pero la diversión continúa:&lt;/div&gt;&lt;div style="background-color: #f0f0ff; padding: 4px 8px 4px 8px; font-size: 90%;line-height:105%;"&gt;Company X is able to eliminate the thousands of stored procedures (&lt;i&gt;que ya funcionaban&lt;/i&gt;) and instead use "automagic" mapping features to generate its SQL. Development costs go down, profits go up and everyone is happy [...]&lt;/div&gt;&lt;div&gt;... especialmente el niño Vijay, que ya tiene el ejemplo canónico que siempre se escribe en los primeros capítulos. Menos mal que enseguida nos aclara que &lt;i&gt;"this is an oversimplified example"&lt;/i&gt;. Menos mal. Porque cuando la magia entra por la puerta, la inteligencia salta corriendo por la ventana.&lt;/div&gt;&lt;div&gt;Vale, reconozco que los escritores solemos rellenar los primeros capítulos con la misma alegría con la que los chinos echaban melamina en la leche para bebés. El problema es que los problemas continúan a lo largo del libro... excepto en las páginas que contienen información irrelevante, o en las que se limitan a tirar de la ayuda. Para no hacer esta masacre demasiado larga, aquí tiene un botón de muestra, sumamente divertido y revelador. El hermanito Vijay intenta explicarnos por qué prefiere no usar &lt;b&gt;var&lt;/b&gt; para declarar variables locales con tipo implícito (p. 149):&lt;/div&gt;&lt;div style="background-color: #f0f0ff; padding: 4px 8px 4px 8px; font-size: 90%;line-height:105%;"&gt;The reason to be explicit with the types is the same reason that you strongly type variables in the world of software development: to make it easier to understand &lt;b&gt;and gain a negligible performance increase&lt;/b&gt;.&lt;/div&gt;&lt;div&gt;&lt;img style="float:right; margin:1px 0 1px 8px;padding:0px;border-style:none;" src="http://1.bp.blogspot.com/_QWaXq7W8dVI/SZtTeDtrwOI/AAAAAAAAAPo/wwkV9UrXUZ0/s320/puppy.jpg" border="0" alt="Heeeelp meeee!" /&gt;Las negritas son mías, por supuesto: resulta que este señor no comprende un sencillísimo truco del lenguaje en que programa, y sin embargo, le recomienda pasar a un sistema que exige un conocimiento en profundidad de ese mismo lenguaje y de su modelo de objetos.&lt;/div&gt;&lt;div&gt;Claro, que si usted se siente molesto conmigo puede dar ejemplo de solidaridad y comprarse el engendro. Pero recuerde que, cada vez que alguien compra un libro malo, el Diablo aparece y mata un cachorrito.&lt;/div&gt;&lt;hr class="p"&gt;&lt;div style="font-size: 90%; font-style: italic; margin-left:24px; margin-right:24px; background-color: #c0c0ff; padding: 4px 8px 4px 8px; line-height:105%;"&gt;La verdad es que me extrañó un poco el ejemplo de la comida para perros. Pero luego recordé que son los musulmanes quienes consideran que el perro es un animal impuro. Los hindúes, en realidad... bueno, no recuerdo si los consideran seres divinos o si se los comen.&lt;/div&gt;&lt;div style="font-size: 90%; font-style: italic; margin-left:24px; margin-right:24px; background-color: #c0c0ff; padding: 4px 8px 4px 8px; line-height:105%;"&gt;Hat tip to Alfredo Novoa: &lt;a href="http://www.diariodelaltoaragon.es/NoticiasDetalle.aspx?Id=556121" target="_blank"&gt;se casan con ellos&lt;/a&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-2533708553819695816?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/2533708553819695816/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=2533708553819695816&amp;isPopup=true' title='146 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2533708553819695816'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2533708553819695816'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2009/02/otra-seta-perdon-libro-sobre-linq.html' title='Otra seta, perdón, libro sobre LINQ'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_QWaXq7W8dVI/SZtTeDtrwOI/AAAAAAAAAPo/wwkV9UrXUZ0/s72-c/puppy.jpg' height='72' width='72'/><thr:total>146</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-3617791425429348232</id><published>2009-02-09T02:07:00.012+01:00</published><updated>2009-02-09T09:32:44.562+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='disparates'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='Design by Contract'/><title type='text'>Garantías</title><content type='html'>&lt;div&gt;&lt;a href="http://www.britannica.com/EBchecked/topic-art/342664/88867/Patricia-Bourne-training-lions-to-stand-on-their-hind-legs"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;border-style:none;padding:0px;" src="http://2.bp.blogspot.com/_QWaXq7W8dVI/SY92FTEjMfI/AAAAAAAAAPc/3jXGig7Y0IU/s320/lions.jpg" border="0" alt="Dorothy se enfrenta a la familia política del León Cobarde" /&gt;&lt;/a&gt;&lt;span class="first"&gt;La Programación no es&lt;/span&gt; trabajo ni para cobardes ni para desmemoriados. La máquina es una bestia salvaje atada por una cadena: si queremos ganarnos la vida con ella, tenemos que despojarnos del miedo irracional. Pero también tenemos que recordar, en todo momento, cuál es la longitud de la puñetera cadena.&lt;/div&gt;&lt;div&gt;Cuando hablo de "cadena", usted debe entender "contrato": cada pieza de software debe dejar bien claro qué es lo que hace por nosotros, siempre que le proporcionemos lo que especifica el contrato. &lt;i&gt;Math.Sqrt&lt;/i&gt; nos calculará la raíz cuadrada de un número, siempre que le proporcionemos un número no negativo. El indexador de la clase genérica &lt;i&gt;Dictionary&lt;/i&gt; nos devolverá el valor asociado a una clave, aunque sólo cuando la clave se haya almacenado antes. Ignorar la existencia de estos contratos nos puede llevar a uno de dos problemas:&lt;/div&gt;&lt;ol&gt;&lt;li&gt;Pedimos la raíz cuadrada de menos uno, y el león nos come una oreja.&lt;/li&gt;&lt;li&gt;El problema anterior suele pasar una sola vez. El aprendiz de domador suele quedar aterrorizado, y de ahí en adelante no se acerca al león, excepto cuando su abogado está presente (para que se coma al león en caso necesario). El abogado, por desgracia, termina siendo un problema mayor que el propio león.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;A continuación, voy a presentarle varias joyas que muestran los problemas que se pueden presentar cuando el programador decide ignorar, por excesivo terror, las garantías que le ofrecen los contratos. El problema con estas "joyas" es que, cuando uno se las encuentra, pierde un tiempo valioso intentando decidir si:&lt;/div&gt;&lt;ol&gt;&lt;li&gt;Se trata de una genialidad.&lt;/li&gt;&lt;li&gt;O se trata de una simple cagada.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;El 99% de los casos corresponde a la segunda opción, pero uno se niega a perder tan pronto la fe en el género humano.&lt;/div&gt;&lt;div&gt;La primera perla negra tiene que ver, como no podía ser de otro modo, con la ya mencionada clase &lt;i&gt;Dictionary&lt;/i&gt;. Estoy harto de ver este fragmento de código en el software de cierta empresa imaginaria:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;if&lt;/b&gt; (dict.ContainsKey(key))&lt;br /&gt;    dict[key] = value;&lt;br /&gt;&lt;b&gt;else&lt;/b&gt;&lt;br /&gt;    dict.Add(key, value);&lt;/pre&gt;&lt;div&gt;Esto podría pasar como buena programación en &lt;a href="http://es.wikipedia.org/wiki/Ankh-Morpork" target="_blank"&gt;Ankh-Morpork&lt;/a&gt;, pero aquí solemos ser un poco más exigentes. Un buen día, uno de los leones, el método &lt;i&gt;Add&lt;/i&gt;, se adelantó al gato y le comió la lengua al programador, cuando éste intentó insertar una clave duplicada en un diccionario. De ese día en adelante, el programador pincha primero el diccionario con una vara larga, para ver si ya existe la clave. En caso afirmativo, &lt;i&gt;actualiza&lt;/i&gt; el valor asociado a la clave; de lo contrario, inserta el nuevo par clave/valor. El problema es que el mismo resultado se obtiene con menos charla:&lt;/div&gt;&lt;pre class="p"&gt;dict[key] = value;&lt;/pre&gt;&lt;div&gt;En efecto, cuando se realiza una asignación sobre el indizador un diccionario, si exista la clave, se actualiza el valor; de lo contrario, se inserta. Hay dos posibilidades: o el programador lo sabía, y se le olvidó... o nunca se tomó la molestia de leerse la documentación. Prefiero pensar lo primero. Al fin y al cabo, la memoria viene genéticamente determinada, y uno no debe reñirle al prójimo por sus genes.&lt;/div&gt;&lt;div&gt;Por cierto, y si me permite el paréntesis, ¿sabía usted que podemos inicializar un diccionario genérico como si se tratase de una vulgar colección? ¡Es que un diccionario genérico es una colección! El quid está en saber qué tipo de colección: sus elementos son instancias de la clase genérica &lt;i&gt;KeyValuePar&lt;/i&gt;. Esta es la técnica:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;private&lt;/b&gt; &lt;font color="darkcyan"&gt;Dictionary&lt;/font&gt;&amp;lt;&lt;b&gt;int&lt;/b&gt;, &lt;b&gt;string&lt;/b&gt;&amp;gt; d =&lt;br /&gt;    &lt;b&gt;new&lt;/b&gt; &lt;font color="darkcyan"&gt;Dictionary&lt;/font&gt;&amp;lt;&lt;b&gt;int&lt;/b&gt;, &lt;b&gt;string&lt;/b&gt;&amp;gt;()&lt;br /&gt;    {&lt;br /&gt;        {1, "Uno"},&lt;br /&gt;        {2, "Dos"},&lt;br /&gt;        {3, "Tres"},&lt;br /&gt;    };&lt;/pre&gt;&lt;div&gt;Preste atención a la coma, aparentemente superflua, que sigue al tercer par de valores. Se trata de un sencillo, pero poco conocido, truco sintáctico que permite añadir o quitar pares, en cualquier momento, sin preocuparnos por el carácter especial del último par. Este mismo truco se aplica a los inicializadores de objetos, e incluso a la declaración de tipos enumerativos. Si le parece una barbaridad y una concesión (hay gente para todo), recuerde que en C&lt;sup&gt;#&lt;/sup&gt; el punto y coma es un terminador, no un separador. ¿Qué hay de malo en querer usar la coma también como terminador, en estos casos?&lt;/div&gt;&lt;div&gt;Vamos ahora a otra garantía que solemos olvidar... o simplemente desconocer. Esta vez, la garantía tiene que ver con el propio lenguaje:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;double&lt;/b&gt; d = 0.0;&lt;br /&gt;&lt;b&gt;if&lt;/b&gt; (cond)&lt;br /&gt;    d = 1.0;&lt;br /&gt;&lt;b&gt;else&lt;/b&gt;&lt;br /&gt;    d = 2.0;&lt;/pre&gt;&lt;div&gt;Naturalmente, la inicialización de la variable local sobra:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;double&lt;/b&gt; d;&lt;br /&gt;&lt;b&gt;if&lt;/b&gt; (cond)&lt;br /&gt;    d = 1.0;&lt;br /&gt;&lt;b&gt;else&lt;/b&gt;&lt;br /&gt;    d = 2.0;&lt;/pre&gt;&lt;div&gt;No pasa nada porque se deje &lt;i&gt;d&lt;/i&gt; sin inicializar... aparentemente. La instrucción que sigue lo garantiza, sin importar cuál de sus ramas se ejecute. Por supuesto, en este caso sencillo, habría sido más fácil escribir todo el código de esta manera:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;double&lt;/b&gt; d = cond ? 1.0 : 2.0;&lt;/pre&gt;&lt;div&gt;El programador que escribió el primer fragmento ha olvidado la sección de la especificación de C&lt;sup&gt;#&lt;/sup&gt; que explica el concepto de &lt;i&gt;asignación definida&lt;/i&gt;. La ha olvidado, o nunca se ha tomado la molestia de leerla.&lt;/div&gt;&lt;div&gt;Otro disparate frecuente debido al temor a lo desconocido:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;private double&lt;/b&gt; f()&lt;br /&gt;{&lt;br /&gt;    &lt;b&gt;double&lt;/b&gt; d = 0.0;&lt;br /&gt;    OpenXXX();&lt;br /&gt;    &lt;b&gt;try&lt;/b&gt; {&lt;br /&gt;        &lt;b&gt;if&lt;/b&gt; (cond)&lt;br /&gt;            d = f1();&lt;br /&gt;        &lt;b&gt;else&lt;/b&gt;&lt;br /&gt;            d = f2();&lt;br /&gt;    }&lt;br /&gt;    &lt;b&gt;finally&lt;/b&gt; {&lt;br /&gt;        CloseXXX();&lt;br /&gt;    }&lt;br /&gt;    &lt;b&gt;return&lt;/b&gt; d;&lt;br /&gt;}&lt;/pre&gt;&lt;div&gt;En realidad, el código anterior combina varios disparates debido al olvido o desconocimiento de las garantías de los contratos. Para empezar, vuelve a sobrarnos la inicialización de la variable local: la rama &lt;b&gt;try&lt;/b&gt; del bloque &lt;b&gt;try&lt;/b&gt;/&lt;b&gt;finally&lt;/b&gt; nos garantiza la asignación definida de la variable, y la rama &lt;b&gt;finally&lt;/b&gt; es irrelevante, si no utilizamos &lt;i&gt;d&lt;/i&gt; en su interior. Tenga en cuenta que, si se ejecuta el &lt;b&gt;finally&lt;/b&gt;, nunca llegaremos a la instrucción &lt;b&gt;return&lt;/b&gt;.&lt;/div&gt;&lt;div&gt;Pero la zarpa que realmente aterra al programador del ejemplo es la posibilidad de ejecutar un &lt;b&gt;return&lt;/b&gt; dentro de la rama &lt;b&gt;try&lt;/b&gt;, por desconocimiento (u olvido) del funcionamiento de esta instrucción. Podemos ejecutar ese &lt;b&gt;return&lt;/b&gt; sin problemas, y el código se simplifica entonces enormemente:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;private double&lt;/b&gt; f()&lt;br /&gt;{&lt;br /&gt;    OpenXXX();&lt;br /&gt;    &lt;b&gt;try&lt;/b&gt; {&lt;br /&gt;        &lt;b&gt;return&lt;/b&gt; cond ? f1() : f2();&lt;br /&gt;    }&lt;br /&gt;    &lt;b&gt;finally&lt;/b&gt; {&lt;br /&gt;        CloseXXX();&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;div&gt;El código simplificado es más corto, más comprensible y, probablemente, algo más eficiente, y ya no hablemos de la elegancia. ¿Moraleja? Conozca sus deberes y derechos, tal y como los especifican los contratos de su software, y así será mejor programador. O, mejor aún: &lt;a href="http://es.wikipedia.org/wiki/RTFM" target="_blank"&gt;RTFM&lt;/a&gt; (again).&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-3617791425429348232?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/3617791425429348232/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=3617791425429348232&amp;isPopup=true' title='10 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/3617791425429348232'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/3617791425429348232'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2009/02/garantias.html' title='Garantías'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_QWaXq7W8dVI/SY92FTEjMfI/AAAAAAAAAPc/3jXGig7Y0IU/s72-c/lions.jpg' height='72' width='72'/><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-340218012427901985</id><published>2009-01-26T12:44:00.018+01:00</published><updated>2009-01-26T18:50:12.209+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='disparates'/><category scheme='http://www.blogger.com/atom/ns#' term='metodología'/><title type='text'>Más extraña que la ficción</title><content type='html'>&lt;div&gt;&lt;img style="float:right; margin:1px 0 1px 8px; border-style:none; padding:0px;" src="http://4.bp.blogspot.com/_QWaXq7W8dVI/SX31cnlShqI/AAAAAAAAAPU/saXSRMcTFzw/s320/witchdoc.jpg" border="0" alt="Si ya tienes un médico brujo, ¿para qué necesitas al Doctor Marteens?" /&gt;&lt;span class="first"&gt;Había una vez&lt;/span&gt; una empresa imaginaria, habitada por &lt;a href="http://commanet.blogspot.com/2008/11/el-escarabajo-pelotero.html"&gt;escarabajos peloteros&lt;/a&gt; que practicaban el &lt;a href="http://commanet.blogspot.com/2008/04/cargocultismo_26.html"&gt;cargocultismo&lt;/a&gt; mientras arrastraban sus fragantes bolitas de excrementos y esperaban el regreso de John Frumm. Un buen día, apareció un feo insecto en sus instalaciones, amenazando con devorar los cimientos corporativos. Para exterminarlo, los escarabajos ejecutaron la danza ritual del &lt;a href="http://commanet.blogspot.com/2008/04/el-pollo-de-skinner.html"&gt;pollo de Skinner&lt;/a&gt; y practicaron un exorcismo.&lt;/div&gt;&lt;div&gt;Demasiado folklore acumulado en un solo punto del espaciotiempo, en mi opinión. Un punto imaginario, quise decir...&lt;/div&gt;&lt;hr class="p"&gt;&lt;div style="font-size: 90%; font-style: italic; margin-left:24px; margin-right:24px; background-color: #c0c0ff; padding: 4px 8px 4px 8px; line-height:105%;"&gt;... y si enmascarar un bug mediante el simple expediente de unir dos instrucciones &lt;b&gt;try&lt;/b&gt;/&lt;b&gt;catch&lt;/b&gt; no es bailar la danza del pollo de Skinner, que vuelva John Frumm y lo vea.&lt;br&gt;&lt;br&gt;Por supuesto, el problema real es que el nido del monstruo sigue estando ahí, no tan evidente como el dinosaurio de Monterroso, pero aún amenazante.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-340218012427901985?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/340218012427901985/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=340218012427901985&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/340218012427901985'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/340218012427901985'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2009/01/ms-extraa-que-la-ficcin.html' title='Más extraña que la ficción'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_QWaXq7W8dVI/SX31cnlShqI/AAAAAAAAAPU/saXSRMcTFzw/s72-c/witchdoc.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-6330051606034478516</id><published>2008-12-16T18:15:00.004+01:00</published><updated>2008-12-16T18:36:49.588+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sincronización'/><category scheme='http://www.blogger.com/atom/ns#' term='bloqueos'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrencia'/><category scheme='http://www.blogger.com/atom/ns#' term='libros'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><title type='text'>Libro sobre concurrencia</title><content type='html'>&lt;div&gt;&lt;iframe src="http://rcm.amazon.com/e/cm?t=callindrmarte-20&amp;o=1&amp;p=8&amp;l=as1&amp;asins=032143482X&amp;fc1=000000&amp;IS2=1&amp;lt1=_blank&amp;m=amazon&amp;lc1=0000FF&amp;bc1=000000&amp;bg1=FFFFFF&amp;f=ifr&amp;nou=1" style="width:120px;height:240px; float:right; margin: 1px 0px 1px 8px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt;&lt;span class="first"&gt;Llevaba anunciándose desde&lt;/span&gt; hace unos cuantos meses, y finalmente está disponible: &lt;i&gt;Concurrent programming on Windows&lt;/i&gt;, de &lt;a href="www.bluebytesoftware.com/blog"&gt;Joe Duffy&lt;/a&gt;, quien, por cierto, nada tiene que ver con la &lt;a href="http://www.youtube.com/watch?v=pp0ce1kS-yw" target="_blank"&gt;señorita&lt;/a&gt; que canta aquello de &lt;i&gt;"You got me begging you for mercy"&lt;/i&gt;...&lt;/div&gt;&lt;div&gt;El libro entra por derecho propio en la categoría &lt;i&gt;tocho&lt;/i&gt;, en el buen sentido de la palabra. Si tiene un poco de cuidado con los testigos potenciales, puede arrojarlo desde una primera planta sobre cualquiera de sus enemigos. Asegúrese antes, sin embargo, de que el destinatario no lleva casco.&lt;/div&gt;&lt;div&gt;Observe que la sigla &lt;i&gt;.NET&lt;/i&gt; no aparece en el título: en realidad, el libro trata sobre concurrencia utilizando el API nativo de Windows y también .NET. Esa es la buena noticia. La mala es que las partes que tratan sobre .NET suelen ir después de las disertaciones sobre el API nativo, y confieso que llego con sueño a la fiesta.&lt;/div&gt;&lt;div&gt;Si usted ya tiene experiencia con hilos y sincronización, puede que el libro no le enseñe muchas cosas nuevas: la culpa no es del autor, por supuesto, sino que a veces en realidad no hay "más allá". Me ocurría, en su momento, con InterBase: muchas personas me preguntaban por qué no escribía un libro sólo sobre InterBase... y la respuesta era y es que no había mucho de lo que escribir.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-6330051606034478516?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/6330051606034478516/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=6330051606034478516&amp;isPopup=true' title='8 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/6330051606034478516'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/6330051606034478516'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/12/libro-sobre-concurrencia.html' title='Libro sobre concurrencia'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-5254401527520025429</id><published>2008-12-15T14:27:00.002+01:00</published><updated>2008-12-15T14:32:44.987+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='descargas'/><category scheme='http://www.blogger.com/atom/ns#' term='controles'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows Forms'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Task panels</title><content type='html'>&lt;div&gt;&lt;span class="first"&gt;Por si a alguien&lt;/span&gt; le hace falta, he subido un fichero a la sección de ejemplos de mi página con el código de un control para &lt;i&gt;paneles de tareas&lt;/i&gt;:&lt;/div&gt;&lt;a href="http://www.marteens.com/ejemplos.htm#taskpanels" target="_blank"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://www.marteens.com/images/taskpanels.gif" border="0" alt="TaskPanels" /&gt;&lt;/a&gt;&lt;div&gt;Haga clic sobre la imagen para ir a la &lt;a href="http://www.marteens.com/ejemplos.htm#taskpanels" target="_blank"&gt;página de ejemplos&lt;/a&gt;, donde encontrará las instrucciones pertinentes.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-5254401527520025429?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/5254401527520025429/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=5254401527520025429&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/5254401527520025429'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/5254401527520025429'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/12/task-panels.html' title='Task panels'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-8250986938518377377</id><published>2008-11-29T17:49:00.017+01:00</published><updated>2008-12-03T12:58:45.244+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='interface'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><title type='text'>Consenting adults, consenting ducks</title><content type='html'>&lt;div&gt;&lt;img style="float:right; margin:1px 0 1px 8px;" src="http://3.bp.blogspot.com/_QWaXq7W8dVI/STZlWk8kfSI/AAAAAAAAAO0/DPUP5_ztmW8/s320/duckula.jpg" border="0" alt="No le toques los colmillos al Conde Duckula" /&gt;&lt;span class="first"&gt;Hace poco, escribía en los&lt;/span&gt; comentarios de otra entrada que esto la Informática no es una ciencia, sino una ingeniería... y Alfredo Novoa respondía que ni siquiera eso. La siguiente anécdota demuestra cuán cierta es, desgraciadamente, esta afirmación.&lt;/div&gt;&lt;div&gt;La historia viene a cuento de una característica "novedosa" llamada &lt;i&gt;duck typing&lt;/i&gt;. Según sus defensores, si una clase tiene métodos &lt;i&gt;Add&lt;/i&gt;, &lt;i&gt;Remove&lt;/i&gt; e &lt;i&gt;Insert&lt;/i&gt;, y un indexador, ¿qué hay de malo en asignar una instancia de la clase a una variable de tipo &lt;i&gt;ICollection&lt;/i&gt;? Eso es, en pocas palabras, el &lt;i&gt;duck typing&lt;/i&gt;: si algo camina como un pato, nada como un pato, vuela como un pato (es decir, las tres cosas las hace mal) y además caga como un pato (es decir, constantemente), entonces, según los adeptos del mecanismo, tiene que ser un pato. Naturalmente, yo digo que puede ser una oca, o un pato robot, o el conde Duckula. No es buena idea tratar al señor conde como a un vulgar pato. Y así lo hice ver aquí, aunque de pasada:&lt;/div&gt;&lt;ul type="square"&gt;&lt;li&gt;&lt;a href="http://commanet.blogspot.com/2007/05/internal-affaires.html"&gt;Internal affaires&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Algún tiempo más tarde, alguien se quejó en un comentario... y como no suelo llevar cuenta de los comentarios tras cierto tiempo, no me percaté del hecho hasta hace un par de días. Esta es el comentario:&lt;/div&gt;&lt;div style="font-size: 90%; font-style: italic; margin-left:24px; margin-right:24px; background-color: #c0c0ff; padding: 4px 8px 4px 8px; line-height:105%;"&gt;Cuál es el problema que le ves al "duck typing". Los que lo utilizan, suponen que los programadores son "consenting adults".&lt;/div&gt;&lt;div&gt;&lt;i&gt;Consenting adults&lt;/i&gt;, eh...&lt;/div&gt;&lt;div&gt;En principio, eso serviría también para justificar las conversiones de tipos bestiales que son el pan de cada día en C++. Al fin y al cabo, si yo sé que un puntero se representa como un entero de 32 bits en mi plataforma, ¿por qué no voy a poder incrementar ese entero en cuatro para acceder al siguiente elemento de un vector? &lt;i&gt;Consenting adults&lt;/i&gt;. No estamos locos. Sabemos lo que queremos...&lt;/div&gt;&lt;div&gt;Ahora bien, ¿es tan peligroso el duck typing como las conversiones bestiales? Veo dos problemas principales:&lt;/div&gt;&lt;ol&gt;&lt;li&gt;Una pila no es simplemente un objeto que tiene dos métodos &lt;i&gt;Push&lt;/i&gt; y &lt;i&gt;Pop&lt;/i&gt;. Esos dos métodos, además, tienen que satisfacer determinado contrato. En la práctica, si el pato es mío, es un descuido mío el que no haya hecho que la clase correspondiente implemente la interfaz deseada. Si el pato es ajeno, es muy peligroso asumir que puedo tratar a un águila como a un pato simplemente porque ambos tienen pico.&lt;/li&gt;&lt;li&gt;Si el pato es ajeno, además, los problemas con el versionado de clases pueden ser peliagudos. O "plumiagudos", si lo prefiere...&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;En cualquier caso, me hace gracia el uso de la teoría de los &lt;i&gt;consenting adults&lt;/i&gt;. Hace poco, en Alemania, un buen señor pidió a otro &lt;i&gt;consenting adult&lt;/i&gt; que le cortase la picha y se la comiese (en ese orden). El otro, efectivamente, cumplió con lo pactado. Luego mató a la víctima, como ésta había solicitado, se comió un muslo, y puso el otro a secarse para hacer jamón. Al caníbal lo pillaron, y lo llevaron a juicio. E inmediatamente, se armó el correspondiente revuelo: ¿por qué condenarlo? ¿No se limitó a hacer lo que el otro pirado le pedía? ¿No eran una parejita de &lt;i&gt;consenting adults&lt;/i&gt;?&lt;/div&gt;&lt;div&gt;Evidentemente, tengo mi propia opinión al respecto. Yo, al canibalizado, si lo pillase antes de ser devorado, no le haría nada. Al fin y al cabo, si quiere que otro lo mate y se lo zampe, es su problema. Es, en efecto, un &lt;i&gt;consenting adult&lt;/i&gt;: se supone que sabe lo que hace. Mi problema es con el caníbal: es un pirado, y tengo serias sospechas de que intentará repetir la acción. La próxima vez, no estoy seguro de que vaya a encontrar un &lt;i&gt;consenting adult&lt;/i&gt; para satisfacer sus antojos culinarios. Es un individuo peligroso. No sé si eso bastará (junto con lo que ya ha hecho) para enviarlo a la cárcel, pero en mi barrio no lo quiero.&lt;/div&gt;&lt;div&gt;Lo mismo se aplica a los &lt;i&gt;duck typers&lt;/i&gt;. ¿De manera que usted es aficionado a transformar el agua en vino, perros en patos y patos en borricos? Ah, claro, usted sabe lo que hace. Pero lo que usted hace es peligroso. No me gustaría verle enredando con mis proyectos...&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-8250986938518377377?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/8250986938518377377/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=8250986938518377377&amp;isPopup=true' title='15 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/8250986938518377377'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/8250986938518377377'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/11/consenting-adults-consenting-ducks.html' title='Consenting adults, consenting ducks'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_QWaXq7W8dVI/STZlWk8kfSI/AAAAAAAAAO0/DPUP5_ztmW8/s72-c/duckula.jpg' height='72' width='72'/><thr:total>15</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-8827014916699995157</id><published>2008-11-28T00:20:00.004+01:00</published><updated>2008-11-28T00:24:41.703+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><category scheme='http://www.blogger.com/atom/ns#' term='Marteens'/><category scheme='http://www.blogger.com/atom/ns#' term='CLR'/><title type='text'>¡No publique vectores!</title><content type='html'>&lt;div&gt;&lt;img style="float:right; margin:1px 0px 1px 8px;border-style:none" src="http://www.marteens.com/nav/nav14.png" border="0" alt="" /&gt;&lt;span class="first"&gt;Nueva píldora orientada&lt;/span&gt; a objetos:&lt;/div&gt;&lt;ul type="square"&gt;&lt;li&gt;&lt;a href="http://www.marteens.com/pills.html#dont_publish_arrays"&gt;Las propiedades o métodos que devuelven vectores son una mala idea&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-8827014916699995157?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/8827014916699995157/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=8827014916699995157&amp;isPopup=true' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/8827014916699995157'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/8827014916699995157'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/11/no-publique-vectores.html' title='¡No publique vectores!'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-7911476052459627416</id><published>2008-11-18T09:50:00.022+01:00</published><updated>2008-11-18T14:44:51.927+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><title type='text'>¡Te lo dije!</title><content type='html'>&lt;div&gt;&lt;img style="float:right; margin:1px 0 1px 8px; border-style:none;" src="http://1.bp.blogspot.com/_QWaXq7W8dVI/SSKJRF2UgBI/AAAAAAAAAOk/leoYXhfSuws/s320/beavis.jpg" border="0" alt="They never scored!" /&gt;&lt;span class="first"&gt;Permítame que me eche&lt;/span&gt; unas risas... ya, sí, ya puedo continuar...&lt;/div&gt;&lt;div&gt;Sin duda, usted conocerá a Beavis y su amiguete Butt-head. Son dos friquis metaleros de dibujos animados, que se pasaban la vida intentando "anotar"; meter un gol, ya me entiende... Cuando la serie llegó a su fin, el creador, jocosamente, escribió un epitafio para sus personajes:&lt;/div&gt;&lt;div style="margin-left: 32px;"&gt;- They never scored.&lt;/div&gt;&lt;div&gt;Nunca "anotaron". Pobrecillos. Lo mismo, por desgracia, se puede decir del compilador de Borland para .NET: nunca llegó a marcar gol. Murió virgen aunque no casto.&lt;/div&gt;&lt;div&gt;¿Una tragedia? Nah. Tragedias son las guerras, el hambre, las enfermedades. Concedo que puede ser una molestia. Mi sabor favorito de Häagen-Dazs ya no se vende en mi barrio. Es molesto, e irritante, eso sí. De todos modos, tengo todo el derecho del mundo a decir: ¡TE LO DIJE!&lt;/div&gt;&lt;h3&gt;... y nada más que la verdad&lt;/h3&gt;&lt;div&gt;Veamos los hechos desnudos: un buen día, la compañía antes conocida como Inprise decide que su negocio de compiladores es una ruina. Segrega la compañía (igual que las babosas segregan un moquillo adherente), bautiza CodeGear al retoño, y anuncia que tiene un montón de novios. Pero la petición de mano se demora infinitamente y toda la villa comienza a sospechar que se trataba de un farol. Tras varias peripecias, aparece el Príncipe Azul, un tal &lt;a href="http://www.embarcadero.com/" target="_blank"&gt;Embarcadero&lt;/a&gt;, cabalgando radiante sobre su moto acuática, y carga con la solterona (¿le habrán pagado para que se la llevase de una puñetera vez?).&lt;/div&gt;&lt;div&gt;Uno esperaría que, tras tan accidentado romance, la parejita se pusiese a fabricar pequeños ogros, como Fiona y Shrek, pero... es que Fiona ya aportaba al enlace dos monstruitos: Delphi para Win32 y Delphi.NET. Ah, sí, y esa abominación de "Delphi para PHP" y otros engendros que mejor dejo sin clasificar. Bueno, menos trabajo para el ogro, ¿o no?&lt;/div&gt;&lt;div&gt;Entonces, la comedia se transforma en drama: Shrek tira Delphi.NET por la ventana y &lt;a href="http://www.codegear.com/products/delphi/prism" target="_blank" title="Delphi Prism"&gt;toma en adopción&lt;/a&gt; el brillante hijo de un vecino, llamado &lt;a href="http://www.remobjects.com/oxygene.aspx" target="_blank"&gt;Oxygen&lt;/a&gt;, aka Chrome. ¿Sabía Shrek lo que iba a hacer con su vástago desde el primer momento? ¿Se convenció a su pesar de que Delphi.NET no tenía arreglo? A todas estas, los representantes de Fiona parecen haberse puesto de acuerdo en mostrar su mejor sonrisa a los medios. Pero uno imagina que la procesión debe ir por dentro...&lt;/div&gt;&lt;h3&gt;El bien o el mal&lt;/h3&gt;&lt;div&gt;No me entienda mal: Oxygen es un producto que me gusta y que recomiendo sin reservas. De hecho, en cierta manera lo considero un familiar cercano. &lt;a href="http://freyalang.blogspot.com" target="_blank"&gt;Freya&lt;/a&gt; ha copiado impúdicamente algunas ideas de Oxygen/Chrome, como la palabra clave &lt;b&gt;method&lt;/b&gt; o los niveles de visibilidad. Muchas características comunes son fruto de una evolución paralela: es un indicio de que ambos proyectos arribaron a los conclusiones lógicas en esos puntos. A la vez, me empeño en creer voluntariosamente que puede que alguna característica de Freya se haya podido filtrar a Oxygen/Chrome.&lt;/div&gt;&lt;div&gt;¿Es el párrafo anterior una recomendación de compra de Delphi Prism? ¡Más despacio, por favor! Si usted odia orgánicamente las llaves, le recomendaría que comprase Oxygen. Delphi Prism es Oxygen más toda la morralla de "compatibilidad" con los obsoletos módulos heredados de CodeGear. ¿Alguien en sus cabales se atreve a programar con dbExpress.NET... cuando dbExpress nativo terminó siendo un fracaso sonado? Si va a programar con Oxygen, mi recomendación es que utilice ADO.NET, o los productos de acceso a datos de &lt;a href="http://www.remobjects.com/"&gt;RemObjects&lt;/a&gt;. Cualquier otra decisión, significaría empantanarse por puro capricho.&lt;/div&gt;&lt;div&gt;En cualquier caso, Embarcadero tiene un bonito problema: Delphi Prism y Delphi for Win32 son dos lenguajes muy diferentes. ¿Tendrá secuela este peliculón?&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-7911476052459627416?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/7911476052459627416/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=7911476052459627416&amp;isPopup=true' title='47 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7911476052459627416'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7911476052459627416'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/11/te-lo-dije.html' title='¡Te lo dije!'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_QWaXq7W8dVI/SSKJRF2UgBI/AAAAAAAAAOk/leoYXhfSuws/s72-c/beavis.jpg' height='72' width='72'/><thr:total>47</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-889946111622659872</id><published>2008-11-17T09:28:00.018+01:00</published><updated>2008-11-17T11:01:11.778+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Windows Forms'/><category scheme='http://www.blogger.com/atom/ns#' term='generics'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Genericidad en vez de typeof</title><content type='html'>&lt;div&gt;&lt;img style="float:right; margin:1px 0 1px 8px;border-style:none;" src="http://3.bp.blogspot.com/_QWaXq7W8dVI/SSE5k5BUUjI/AAAAAAAAAOc/QwEL1fl8kWY/s320/cube.jpg" border="0" alt="" /&gt;&lt;span class="first"&gt;Permítame un&lt;/span&gt; breve descanso entre tantos disparates. He estado usando últimamente una técnica sencilla y conocida para identificar posibilidades de simplificación en código heredado de .NET v1.1. La técnica consiste en buscar métodos, en el código fuente, que reciban un parámetro de tipo &lt;i&gt;System.Type&lt;/i&gt;, para considerar la posibilidad de convertir dicho método en un método genérico.&lt;/div&gt;&lt;div&gt;El caso típico se encuentra casi siempre en el "gestor" de ventanas:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;public interface&lt;/b&gt; &lt;font color="darkcyan"&gt;IFormManager&lt;/font&gt;&lt;br /&gt;{&lt;br /&gt;    &lt;font color="darkcyan"&gt;Form&lt;/font&gt; ShowForm(&lt;font color="darkcyan"&gt;Type&lt;/font&gt; formType);&lt;br /&gt;}&lt;/pre&gt;&lt;div&gt;&lt;i&gt;ShowForm&lt;/i&gt; recibe un tipo de ventana como parámetro, y debe encontrar una ventana abierta cuyo tipo sea exactamente el especificado. Si la encuentra, debe activarla y pasarla a primer plano. En caso contrario, debe crear una ventana de este tipo, y mostrarla. La regla que he mencionado establece que el método anterior debería transformarse en algo parecido a lo siguiente:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;public interface&lt;/b&gt; &lt;font color="darkcyan"&gt;IFormManager&lt;/font&gt;&lt;br /&gt;{&lt;br /&gt;    T ShowForm&amp;lt;T&amp;gt;()&lt;br /&gt;        &lt;b&gt;where&lt;/b&gt; T: &lt;font color="darkcyan"&gt;Form&lt;/font&gt;, &lt;b&gt;new&lt;/b&gt;();&lt;br /&gt;}&lt;/pre&gt;&lt;div&gt;Puntos a destacar:&lt;/div&gt;&lt;ol&gt;&lt;li&gt;El parámetro de tipo &lt;i&gt;T&lt;/i&gt; se ha restringido de dos maneras. En primer lugar, debe ser una clase descendiente de &lt;i&gt;Form&lt;/i&gt;. Usted, naturalmente, puede exigir de sus ventanas que desciendan de alguna clase más concreta, o que implementen algún tipo de interfaz general, o ambas cosas a la vez.&lt;/li&gt;&lt;li&gt;Por otra parte, he exigido que las ventanas tengan un constructor sin parámetros. Este es un requisito opcional, que no valdrá en todos los casos, pero que he incluido aquí para simplificar un poco el código.&lt;/li&gt;&lt;li&gt;Observe que será imposible, al utilizar este método, que el compilador pueda "inferir" el parámetro de tipo. Si no ha trabajado aún con la inferencia de tipos en llamadas a métodos genéricos, traduzca la oración anterior así: &lt;i&gt;"siempre tendremos que indicar explícitamente el tipo de ventana"&lt;/i&gt; (algo bastante razonable).&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;¿Qué hemos ganado con esta transformación? Antes, para mostrar una ventana, teníamos que escribir código como el siguiente:&lt;/div&gt;&lt;pre class="p"&gt;&lt;i&gt;&lt;font color="green"&gt;// "manager" implementa "IFormManager"&lt;/font&gt;&lt;/i&gt;&lt;br /&gt;&lt;font color="darkcyan"&gt;MiVentana&lt;/font&gt; v = manager.ShowForm(&lt;br /&gt;    &lt;b&gt;typeof&lt;/b&gt;(&lt;font color="darkcyan"&gt;MiVentana&lt;/font&gt;)) &lt;b&gt;as&lt;/b&gt; &lt;font color="darkcyan"&gt;MiVentana&lt;/font&gt;;&lt;/pre&gt;&lt;div&gt;Si no efectuamos la conversión de tipos, obtendremos como resultado un valor de tipo &lt;i&gt;Form&lt;/i&gt;, sin más adornos. En cambio, con la versión genérica obtendremos el tipo originalmente deseado:&lt;/div&gt;&lt;pre class="p"&gt;&lt;font color="darkcyan"&gt;MiVentana&lt;/font&gt; v = manager.ShowForm&amp;lt;&lt;font color="darkcyan"&gt;MiVentana&lt;/font&gt;&amp;gt;();&lt;/pre&gt;&lt;div&gt;Para cerrar el círculo, le mostraré una sencilla implementación inicial del tipo de interfaz:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;public class&lt;/b&gt; &lt;font color="darkcyan"&gt;FormManager&lt;/font&gt; : &lt;font color="darkcyan"&gt;IFormManager&lt;/font&gt;&lt;br /&gt;{&lt;br /&gt;    &lt;b&gt;private&lt;/b&gt; &lt;font color="darkcyan"&gt;List&lt;/font&gt;&amp;lt;&lt;font color="darkcyan"&gt;Form&lt;/font&gt;&amp;gt; forms = &lt;b&gt;new&lt;/b&gt; &lt;font color="darkcyan"&gt;List&lt;/font&gt;&amp;lt;&lt;font color="darkcyan"&gt;Form&lt;/font&gt;&amp;gt;();&lt;br /&gt;&amp;nbsp;&lt;br /&gt;    &lt;b&gt;public&lt;/b&gt; T ShowForm&amp;lt;T&amp;gt;()&lt;br /&gt;        &lt;b&gt;where&lt;/b&gt; T: &lt;font color="darkcyan"&gt;Form&lt;/font&gt;, &lt;b&gt;new&lt;/b&gt;()&lt;br /&gt;    {&lt;br /&gt;        &lt;b&gt;foreach&lt;/b&gt; (&lt;b&gt;var&lt;/b&gt; f &lt;b&gt;in&lt;/b&gt; forms)&lt;br /&gt;            &lt;b&gt;if&lt;/b&gt; (f.GetType() == &lt;b&gt;typeof&lt;/b&gt;(T))&lt;br /&gt;            {&lt;br /&gt;                f.Show();&lt;br /&gt;                f.BringToFront();&lt;br /&gt;                &lt;b&gt;return&lt;/b&gt; f &lt;b&gt;as&lt;/b&gt; T;&lt;br /&gt;            }&lt;br /&gt;        &lt;b&gt;var&lt;/b&gt; frm = &lt;b&gt;new&lt;/b&gt; T() { Visible = &lt;b&gt;true&lt;/b&gt; };&lt;br /&gt;        frm.FormClosed += (sender, e) =&amp;gt;&lt;br /&gt;            forms.Remove((&lt;font color="darkcyan"&gt;Form&lt;/font&gt;)sender);&lt;br /&gt;        forms.Add(frm);&lt;br /&gt;        &lt;b&gt;return&lt;/b&gt; frm;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;div&gt;Creo que la primera parte, la que ejecuta el bucle, es fácil de comprender. Luego he complicado un poco las cosas: observe que puedo ejecutar el constructor sin parámetros del tipo &lt;i&gt;T&lt;/i&gt; gracias a las restricciones establecidas sobre el parámetro genérico. Si mis ventanas no se pudiesen construir de esa manera, sino que requiriesen parámetros, entonces tendría que utilizar un poco de reflexión. Tenga presente, no obstante, que la ejecución de un constructor sin parámetros sobre un parámetro de tipo genérico es implementada por el compilador como una llamada al API de reflexión (lo sé porque Freya hace exactamente lo mismo).&lt;/div&gt;&lt;div&gt;¿Ve esas llaves tras la llamada al constructor? Se trata simplemente de una asignación a la propiedad &lt;i&gt;Visible&lt;/i&gt; del formulario recién creado. Podía haberla sustituido por una llamada al método &lt;i&gt;Show&lt;/i&gt;, pero quise mostrar un ejemplo de inicialización de objetos. Luego, resolvemos un problema más serio: &lt;i&gt;FormManager&lt;/i&gt; lleva una lista de las ventanas abiertas (o abiertas e invisibles). Las ventanas se añaden al ser creadas, pero ¿cuándo se eliminan de esta lista? Para ello, asociamos un manejador al evento &lt;i&gt;FormClosing&lt;/i&gt; de cada nueva ventana. En vez de crear el manejador como un método independiente, he preferido utilizar una expresión lambda.&lt;/div&gt;&lt;hr class="p"&gt;&lt;div style="font-size: 90%; font-style: italic; margin-left:24px; margin-right:24px; background-color: #c0c0ff; padding: 4px 8px 4px 8px; line-height:105%;"&gt;Comentarios adicionales: ¿para qué hace falta una interfaz IFormManager? ¿No sería más sencillo diseñar ShowForm como un método estático, dentro de una clase estática? La clave del uso de IFormManager está en la posibilidad de usar diferentes implementaciones según nos convenga. La manía de recurrir a métodos estáticos a la primera es una manifestación de lo que yo llamo "la fiebre del singleton". Es cierto que, al final, nuestro gestor de ventana tendrá que proveer algún singleton, como la variable "manager" de mi ejemplo de uso. Pero la aparición del singleton debe retrasarse todo lo que podamos.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-889946111622659872?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/889946111622659872/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=889946111622659872&amp;isPopup=true' title='5 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/889946111622659872'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/889946111622659872'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/11/genericidad-en-vez-de-typeof.html' title='Genericidad en vez de typeof'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_QWaXq7W8dVI/SSE5k5BUUjI/AAAAAAAAAOc/QwEL1fl8kWY/s72-c/cube.jpg' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-7782196481208203591</id><published>2008-11-12T23:13:00.015+01:00</published><updated>2008-11-17T00:46:51.759+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='disparates'/><category scheme='http://www.blogger.com/atom/ns#' term='cargocultismo'/><category scheme='http://www.blogger.com/atom/ns#' term='metodología'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Antología del Disparate - III</title><content type='html'>&lt;div style="font-style:italic;text-align:right;"&gt;Advertencia: Cualquier parecido con&lt;br /&gt;la coincidencia, es sólo una sospechosa irrealidad...&lt;/div&gt;&lt;div&gt;&lt;img style="float:right; margin:1px 0 1px 6px;border-style:none;padding:0px;" src="http://2.bp.blogspot.com/_QWaXq7W8dVI/SRtb0Fm89MI/AAAAAAAAAKA/ZGQPbXKVcsE/s320/skid.jpg" border="0" alt="Primero uno resbala..." /&gt;&lt;span class="first"&gt;&lt;img style="float:left; margin:4px 2px 0px 0px;border-style:none;padding:0px;" src="http://4.bp.blogspot.com/_QWaXq7W8dVI/SRtVTtDIpsI/AAAAAAAAAJ4/XQijNMe3l1E/s320/cap_c.png" border="0" alt="" /&gt;uando, meses atrás,&lt;/span&gt; se me ocurrió la idea de escribir sobre el &lt;a href="http://commanet.blogspot.com/2008/04/cargocultismo_26.html" target="_blank"&gt;cargocultismo&lt;/a&gt; estaba pensando, en particular, en el problema artificial, creado por mis amigos imaginarios, que voy a discutir a continuación. Repasemos la definición: el &lt;i&gt;cargocultista&lt;/i&gt; es el individuo que practica determinados rituales técnicos porque sabe, o ha oído decir, que a otros les funcionan, pero sin comprender realmente cómo se supone que tienen que funcionar.&lt;/div&gt;&lt;div&gt;En el mundo de la programación, uno de esos rituales misteriosos tiene que ver con la creación de &lt;i&gt;gestores&lt;/i&gt; especiales para distintos módulos de la aplicación, sobre todo cuando se trata de proyectos grandes. Una aplicación "decente" tiene que definir, por fuerza, un "gestor" de menúes, un "gestor" de excepciones, un "gestor" de formularios... y así hasta el aburrimiento o la bancarrota. Para ser exactos, una parte importante de esta secta de cargocultistas no utiliza la palabra "gestor" sino &lt;i&gt;manager&lt;/i&gt;, que se supone que debe darle un poco más de dignidad al engendro.&lt;/div&gt;&lt;div&gt;&lt;img style="float:right; margin:1px 0 1px 6px;border-style:none;padding:0px;" src="http://1.bp.blogspot.com/_QWaXq7W8dVI/SRtcMS4iheI/AAAAAAAAAKI/cqifGBKsCRE/s320/water.jpg" border="0" alt="... y luego, si no tienes cuidado, te la pegas." /&gt;Como suele ocurrir en todos los casos de cargocultismo, la propia idea de un gestor de menúes y ventanas no es mala. ¡Todo lo contrario! Estos módulos suelen ahorrar mucho código repetitivo, y tienen la bonita propiedad de dejarse reutilizar fácilmente de un proyecto al siguiente. Incluso cuando se utilizan en un único proyecto, nos ofrecen la libertad de hacer cambios notables en la interfaz de usuario sin necesidad de retocar todo el código. Visual Studio, por ejemplo, nos permite elegir entre una aplicación MDI tradicional o una en la que los documentos aparecen en páginas paralelas accesibles por pestañas. Lo verdaderamente malo, es inventarse uno de estos gestores sin saber por qué, para qué o cómo.&lt;/div&gt;&lt;h3&gt;Cuello de botella&lt;/h3&gt;&lt;div&gt;A diferencia de disparates anteriores, esta vez el problema no está en una simple instrucción equivocada, sino en el diseño global de un módulo. Los problemas comienzan con la decisión, consciente o inconsciente, de esta gente de ignorar el mecanismo preestablecido para la traducción en .NET y de montar un barroco sistema basado en ficheros XML externos. El vínculo entre cada elemento de la interfaz y su correspondiente cadena se realiza manualmente. Supongamos que usted quiere añadir una etiqueta a un formulario que debe decir &lt;i&gt;"Total"&lt;/i&gt;. De acuerdo a la metodología de estos señores:&lt;/div&gt;&lt;ol&gt;&lt;li&gt;Primero debe ocurrírsele un nombre global para identificar la etiqueta. No se les ocurrió generar ese nombre a partir del nombre del control y del formulario donde se encuentra.&lt;/li&gt;&lt;li&gt;Luego tiene que ir a cada fichero XML de traducción y crear una entrada que traduzca el identificador al correspondiente idioma.&lt;/li&gt;&lt;li&gt;Cada formulario tiene un método &lt;i&gt;Traducir&lt;/i&gt;. No crea que se trata de un método virtual heredado: la herencia visual es algo desconocido en esta metodología. Tiene que añadir una instrucción manualmente a &lt;i&gt;Traducir&lt;/i&gt; en la que asignará a la propiedad &lt;i&gt;Text&lt;/i&gt; de la etiqueta, el resultado de una llamada explícita a un método que busca en un diccionario en memoria la traducción correspondiente.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;Usted se dirá que... bueno, es bastante trabajo, claro... pero con un poco de disciplina... etc, etc. ¡Ah, cuán equivocado estaría! ¿No le he dicho aún que esta gente trabajaba con SourceSafe, para el control de versiones? Imagine lo que ocurre cada vez que dos programadores intentan programar dos formularios que nada tienen que ver entre sí: ¡se tienen que pegar por el acceso a los ficheros de idiomas!&lt;/div&gt;&lt;div&gt;De todas maneras, aunque no se produjese este increíble cuello de botella, el sistema es inaceptable:&lt;/div&gt;&lt;ol&gt;&lt;li&gt;Microsoft ofrece, de serie y sin coste adicional, un mecanismo idéntico en funcionalidad y sin ninguno de estos problemas: ficheros de recursos y ensamblados satélites.&lt;/li&gt;&lt;li&gt;El sistema de Microsoft no le obliga a añadir código manualmente en ningún momento.&lt;/li&gt;&lt;li&gt;El sistema de Microsoft le permitiría, incluso, ahorrar trabajo suponiendo la existencia de un "idioma neutro", para el cuál no tendría que mantener una tabla de recursos adicional.&lt;/li&gt;&lt;li&gt;El sistema de Microsoft es verificable en tiempo de compilación: si compila, funcionará. En cambio, el invento en cuestión utiliza cadenas como claves en el diccionario. Resulta imposible verificar automáticamente la existencia de errores de mecanografía. Por supuesto, si esta gente hubiese usado enumerativos para las claves, el problema se resolvería... pero los dioses ciegan a aquellos a quienes quieren destruir.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;Moraleja parcial: no hay que reinventar la rueda, si además, va a rodar más despacio.&lt;/div&gt;&lt;h3&gt;Escarnio de la locura&lt;/h3&gt;&lt;div&gt;Pues bien, queridos amiguitos, hay también un menú diseñado de acuerdo a esta locura con sistema. Hay claves con formato de cadenas, que tienen que transmitirse desde el código al fichero externo y viceversa, hay versiones del menú para cada idioma soportado y todo lo demás. Pero me voy a centrar en un aspecto muy concreto: en cómo se maneja la ejecución de los comandos del menú.&lt;/div&gt;&lt;div&gt;Cada vez que se ejecuta un comando del menú principal, se invoca un manejador de eventos situado en la ventana principal. No crea que hay un manejador diferente para cada comando, lo cuál habría sido relativamente sencillo de conseguir: todos los comandos van a parar al mismo método. Y ese método, cómo no, contiene una inmensa instrucción &lt;b&gt;switch&lt;/b&gt;, que toma la cadena de caracteres designada como clave del comando para ejecutar el código apropiado.&lt;/div&gt;&lt;div&gt;¿Y en qué consiste ese "código apropiado"? Maravíllese: en una llamada a un método global estático de una clase independiente, a la que llamaremos &lt;i&gt;Acciones&lt;/i&gt;, que se encuentra en un gigantesco fichero C&lt;sup&gt;#&lt;/sup&gt;.&lt;/div&gt;&lt;ul type="disc"&gt;&lt;li&gt;Nuevamente, tenemos un fichero que se convierte en un cuello de botella.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Claro, los conflictos por el acceso al fichero de acciones sólo tendrían que surgir cuando se modificase la estructura del menú... ¿o no? Resulta que no: cuando esta gente tiene que mostrar una ventana que permite una sola instancia, incluye, en el fichero de acciones, un bucle explícito para buscar si existe ya una instancia del tipo de ventanas en una lista global. Si la encuentran, la activan. Y si no, la crean. Y este código se repite tropecientas y tantas veces, una por cada ventana de este tipo, en el fichero de acciones.&lt;/div&gt;&lt;ul type="disc"&gt;&lt;li&gt;Con un poco de reflexión, el código común se podría haber reducido a una simple llamada.&lt;/li&gt;&lt;li&gt;Pero mejor aún, el &lt;b&gt;switch&lt;/b&gt; original ni siquiera tendría que haber pasado por la clase &lt;i&gt;Acciones&lt;/i&gt;, sino que tendría que llamar directamente a métodos estáticos de las clases de ventanas correspondientes. De esa manera, cualquier cambio en la forma de mostrar una ventana, se aislaría dentro del código de la propia ventana.&lt;/li&gt;&lt;li&gt;Para rematar, esta gente ni siquiera utilizó una metodología uniforme para la creación y activación. A veces llamaban a &lt;i&gt;Show&lt;/i&gt;, otras veces combinaban &lt;i&gt;BringToFront&lt;/i&gt;, &lt;i&gt;Activate&lt;/i&gt; y &lt;i&gt;Focus&lt;/i&gt;; a veces cambiaban la forma del cursor, y en otros casos, mostraban una ventana &lt;i&gt;splash&lt;/i&gt; con el mensaje &lt;i&gt;"Espere un poco..."&lt;/i&gt;. Esto complica mucho limpiar el código.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Con todo, lo peor es que a estar alturas todavía les cuesta creer que este sistema sea un error: el cargocultismo susurró en sus oídos que necesitaban un "gestor de menúes" para su aplicación "seria", y ahora tiemblan cada vez que mis tijeras podan porciones cada vez mayores de este cadáver exquisito. Mientras limpio los fluídos putrefactos de mis instrumentos de corte, veo ojos asustados y oigo el coro de plañideras a mi alrededor. Sonrío tranquilizadoramente, pero compruebo que mi sonrisa parece cada día más siniestra.&lt;/div&gt;&lt;div&gt;Y es que uno termina hartándose, ¿sabe?&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-7782196481208203591?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/7782196481208203591/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=7782196481208203591&amp;isPopup=true' title='11 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7782196481208203591'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7782196481208203591'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/11/antologa-del-disparate-iii.html' title='Antología del Disparate - III'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_QWaXq7W8dVI/SRtb0Fm89MI/AAAAAAAAAKA/ZGQPbXKVcsE/s72-c/skid.jpg' height='72' width='72'/><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-3137323643122124044</id><published>2008-11-11T00:03:00.013+01:00</published><updated>2008-11-11T00:23:15.034+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sincronización'/><category scheme='http://www.blogger.com/atom/ns#' term='bloqueos'/><category scheme='http://www.blogger.com/atom/ns#' term='disparates'/><category scheme='http://www.blogger.com/atom/ns#' term='boxing'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='hilos'/><title type='text'>Antología del Disparate - II</title><content type='html'>&lt;div style="font-style:italic;text-align:right;"&gt;Advertencia: Cualquier parecido con&lt;br /&gt;la realidad, es sólo una sospechosa coincidencia...&lt;/div&gt;&lt;div&gt;&lt;span class="first"&gt;&lt;img style="float:left; margin:4px 2px 0px 0px;border-style:none;padding:0px;" src="http://1.bp.blogspot.com/_QWaXq7W8dVI/SRjAGXxB5GI/AAAAAAAAAJo/hj5OHD3U-vc/s320/cap_e.png" border="0" alt="" /&gt;&lt;img style="float:right; margin:1px 0 1px 8px;border-style:none;" src="http://3.bp.blogspot.com/_QWaXq7W8dVI/SRi-akNiG0I/AAAAAAAAAJg/ByTvEORxLNQ/s320/boxing.png" border="0" alt="Boxing" /&gt;stamos otra vez en&lt;/span&gt; una aplicación que maneja un buen puñado de hilos. El "genio" que la programa ya ha tomado consciencia de los peligros de la falta de sincronización, y dedica su tiempo libre a repartir bloqueos a diestra y siniestra. Este es un bello ejemplo de cómo se las gasta el caballerete (imaginario, &lt;i&gt;of course&lt;/i&gt;):&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;private bool&lt;/b&gt; flag;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;&lt;b&gt;public void&lt;/b&gt; YoQueSe()&lt;br /&gt;{&lt;br /&gt;    &lt;b&gt;if&lt;/b&gt; (&lt;font color="darkcyan"&gt;Monitor&lt;/font&gt;.TryEnter(flag))&lt;br /&gt;    {&lt;br /&gt;        &lt;i&gt;// Código "sincronizado" ...&lt;/i&gt;&lt;br /&gt;        &lt;font color="darkcyan"&gt;Monitor&lt;/font&gt;.Exit(flag);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;div&gt;¿Puede ver los disparates? Son varios, por supuesto. ¿Cómo cree que se manifestó el problema? ¿Se atreve a imaginar cómo se le pudo haber ocurrido esta barbaridad a su perpetrador?&lt;/div&gt;&lt;hr class="p"&gt;&lt;div&gt;Esta es, amigo mío, la declaración del método &lt;i&gt;TryEnter&lt;/i&gt; de la clase &lt;i&gt;Monitor&lt;/i&gt;:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;public static bool&lt;/b&gt; TryEnter(&lt;b&gt;object&lt;/b&gt; obj);&lt;/pre&gt;&lt;div&gt;Como puede ver, el parámetro del método debe ser un &lt;i&gt;Object&lt;/i&gt;, o más exactamente, una referencia a un objeto. Como &lt;i&gt;Object&lt;/i&gt; es la clase base final del CLR, cualquier cosa que pasemos como parámetro servirá, a efectos del sistema de tipos. El método incluso admite que pasemos un valor de tipo &lt;i&gt;Boolean&lt;/i&gt;...&lt;/div&gt;&lt;div&gt;... con la única pega de que &lt;i&gt;Boolean&lt;/i&gt; es una estructura, un tipo con semántica de asignación por valor. Para poder pasar un &lt;i&gt;Boolean&lt;/i&gt; donde se espera un objeto, .NET aplica la operación llamada &lt;i&gt;boxing&lt;/i&gt; al valor. Es decir, crea un objeto temporal del tamaño adecuado, y copia en su interior el valor que queríamos pasar. ¿No queríamos una &lt;i&gt;referencia&lt;/i&gt;? Tras el &lt;i&gt;boxing&lt;/i&gt; ya tenemos una.&lt;/div&gt;&lt;div&gt;¿Y qué hay con la llamada final a &lt;i&gt;Exit&lt;/i&gt;? Este es el prototipo de este segundo método:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;public static void&lt;/b&gt; Exit(&lt;b&gt;object&lt;/b&gt; obj);&lt;/pre&gt;&lt;div&gt;Nuevamente, nos piden un objeto. Y el compilador no protesta si pasamos un valor de tipo &lt;i&gt;Boolean&lt;/i&gt;. Simplemente mete el valor en una "cajita" y pasa el puntero a ésta. ¿La pena? Pues que las llamadas a &lt;i&gt;TryEnter&lt;/i&gt; y &lt;i&gt;Exit&lt;/i&gt; deberían utilizar &lt;b&gt;el mismo objeto&lt;/b&gt;... y cada vez que se realiza el &lt;i&gt;boxing&lt;/i&gt;, ¡se crea una instancia temporal diferente!&lt;/div&gt;&lt;div&gt;¿Qué consecuencias cree que tenía el disparate? Sorprendentemente, ¡ninguna!... al menos, mientras la aplicación se mantuvo ejecutando sobre .NET v1.1. Fue al migrar a .NET 3.5 que estos errores empezaron a ser detectados &lt;a href="http://msdn.microsoft.com/en-us/magazine/cc163606.aspx" target="_blank"&gt;en tiempo de depuración&lt;/a&gt;. La llamada a &lt;i&gt;Exit&lt;/i&gt; comenzó a generar una excepción, advirtiendo que se intentaba desbloquear a través de un objeto no bloqueado. Claro, sería una estupidez que el CLR tuviese que verificar en cada llamada a &lt;i&gt;Exit&lt;/i&gt; que el objeto pasado no sea una instancia creada por &lt;i&gt;boxing&lt;/i&gt;: penalizaría a los buenos programadores para evitar que los peores metiesen la pata.&lt;/div&gt;&lt;div&gt;¿Se da cuenta de que, ni siquiera en .NET v1.1, la aplicación estaba protegiendo la sección de código de marras? Si en algún momento se produjeron errores de sincronización en dicha sección, o fueron ignorados... o se perdieron gracias a la demencial política de manejos de excepciones de mi aplicación imaginaria. Observe que hay un segundo error en el código mostrado: se supone que las llamadas a &lt;i&gt;TryEnter&lt;/i&gt; y &lt;i&gt;Exit&lt;/i&gt; deberían estar asociadas a una instrucción &lt;b&gt;try&lt;/b&gt;/&lt;b&gt;finally&lt;/b&gt;.&lt;/div&gt;&lt;div&gt;Y ahora viene lo mejor: ¿cómo imagina que se le ocurrió la burrada al genio? El uso de &lt;i&gt;TryEnter&lt;/i&gt; nos permite reconstruir los hechos. En realidad, el aprendiz de brujo intentó usar la instrucción &lt;b&gt;lock&lt;/b&gt; en primer lugar. ¡Pero &lt;b&gt;lock&lt;/b&gt; sí que puede detectar cuando alguien le pasa una estructura en vez de una referencia! Y como &lt;b&gt;lock&lt;/b&gt; no se dejaba violentar, el muy pillo tradujo el código que suponía que se generaba para dicha instrucción. Pero como manazas que es, incluso eso lo hizo mal...&lt;/div&gt;&lt;div&gt;Moraleja: odio repetirme pero, por favor, esos genios que deambulan por ahí, ¡&lt;a href="http://es.wikipedia.org/wiki/RTFM" target="_blank"&gt;RTFM&lt;/a&gt;!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-3137323643122124044?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/3137323643122124044/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=3137323643122124044&amp;isPopup=true' title='7 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/3137323643122124044'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/3137323643122124044'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/11/antologa-del-disparate-ii_11.html' title='Antología del Disparate - II'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_QWaXq7W8dVI/SRjAGXxB5GI/AAAAAAAAAJo/hj5OHD3U-vc/s72-c/cap_e.png' height='72' width='72'/><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-8394585479637146413</id><published>2008-11-10T17:15:00.027+01:00</published><updated>2008-11-11T00:23:31.342+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sincronización'/><category scheme='http://www.blogger.com/atom/ns#' term='disparates'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='hilos'/><category scheme='http://www.blogger.com/atom/ns#' term='CLR'/><title type='text'>Antología del Disparate - I</title><content type='html'>&lt;div style="font-style:italic;text-align:right;"&gt;Advertencia: Cualquier parecido con&lt;br /&gt;la realidad, es una cochina casualidad...&lt;/div&gt;&lt;div&gt;&lt;img style="float:right; margin:1px 0 1px 8px;border-style:none;padding:0px;" src="http://4.bp.blogspot.com/_QWaXq7W8dVI/SRiomksDoKI/AAAAAAAAAJY/rDlD-BURq-Q/s320/lock.png" border="0" alt="" /&gt;&lt;span class="first"&gt;&lt;img style="float:left; margin:4px 2px 0px 0;border-style:none;padding:0px;" src="http://3.bp.blogspot.com/_QWaXq7W8dVI/SRjBf8i12bI/AAAAAAAAAJw/1E1AtgbXFjA/s320/cap_u.png" border="0" alt="" /&gt;n buen señor, presuntamente&lt;/span&gt; un experto en casi todo, bien pagado y considerado, recibe el encargo de crear una "base de datos en memoria"... tarea que, para el resto de nosotros, los mortales, consiste en meter objetos en un contenedor. Monta su colección basada en &lt;i&gt;ICollection&lt;/i&gt; (estamos en los remotos tiempos de .NET v1.1) y añade internamente un par de &lt;i&gt;Hashtable&lt;/i&gt;'s para permitir el acceso directo dada una clave. Como las "cosas" que tiene que guardar en el contenedor no tienen una clave primaria clara, decide con buen tino añadir una clave artificial, que implementa de la siguiente manera:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;public class&lt;/b&gt; &lt;font color="darkcyan"&gt;Cosa&lt;/font&gt;&lt;br /&gt;{&lt;br /&gt;    &lt;b&gt;private static int&lt;/b&gt; staticId;&lt;br /&gt;    &lt;b&gt;private int&lt;/b&gt; instanceId;&lt;br /&gt;&lt;br /&gt;    &lt;i&gt;// ...&lt;/i&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;div&gt;El campo estático &lt;i&gt;staticId&lt;/i&gt; contiene el valor a asignar a la próxima "cosa" que se cree, mientras que &lt;i&gt;instanceId&lt;/i&gt; representa la clave única y artificial de cada instancia. Esta clave, como sospechará, se asigna automáticamente durante la construcción de instancias.&lt;/div&gt;&lt;div&gt;El problema es que la aplicación en cuestión consume hilos a manos llenas, y es posible que se creen dos "cosas" a la misma vez. Nuestro sujeto, que no es del todo lerdo, sabe que tiene que protegerse, y diseña el siguiente constructor:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;public&lt;/b&gt; Cosa()&lt;br /&gt;{&lt;br /&gt;    &lt;i&gt;// ¡INCORRECTO!&lt;/i&gt;&lt;br /&gt;    &lt;font color="darkcyan"&gt;Interlocked&lt;/font&gt;.Increment(&lt;b&gt;ref&lt;/b&gt; staticId);&lt;br /&gt;    instanceId = staticId;&lt;br /&gt;}&lt;/pre&gt;&lt;div&gt;¿Dónde está el disparate? ¿Cómo, y cuándo, cree usted que se manifestará? ¿Cómo se puede corregir?&lt;/div&gt;&lt;hr class="p"&gt;&lt;div&gt;El disparate, evidentemente, está en el uso incorrecto de la clase &lt;i&gt;Interlocked&lt;/i&gt;. Se trata, en realidad, de un caso flagrante de &lt;a href="http://commanet.blogspot.com/2008/04/cargocultismo_26.html" target="_blank"&gt;cargocultismo&lt;/a&gt;. El "experto" conocía un par de datos correctos:&lt;/div&gt;&lt;ul&gt;&lt;li&gt;El patrón de asignación de un identificador autoincremental exige el uso de primitivas de sincronización, o de lo contrario, pueden producirse anomalías.&lt;/li&gt;&lt;li&gt;La clase &lt;i&gt;Interlocked&lt;/i&gt; permite sustituir determinados usos de la instrucción &lt;b&gt;lock&lt;/b&gt; de forma más eficiente.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Hasta ahí, todo bien: el experto había oído sonar campanas. Lo malo es que no sabía dónde. No se tomó la molestia de leerse hasta el final la ayuda de &lt;i&gt;Interlocked&lt;/i&gt; (¿para qué?). Peor aún: no se preguntó cómo demonios se las arregla esta clase para que el código sea equivalente a un &lt;b&gt;lock&lt;/b&gt; en toda regla. El concepto de "actualización atómica" le resultó tan extraño como escuchar a un marine hablar con Alpha Bravo Charlie a través de su mágica radio-cocotero.&lt;/div&gt;&lt;div&gt;Para explicar qué es lo que está mal en el código original, es mejor que le presente el código correcto:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;public&lt;/b&gt; Cosa()&lt;br /&gt;{&lt;br /&gt;    &lt;i&gt;// ¡CORRECTO!&lt;/i&gt;&lt;br /&gt;    instanceId = &lt;font color="darkcyan"&gt;Interlocked&lt;/font&gt;.Increment(&lt;b&gt;ref&lt;/b&gt; staticId);&lt;br /&gt;}&lt;/pre&gt;&lt;div&gt;Como ve, el arreglo es sencillo: hay que asignar a &lt;i&gt;instanceId&lt;/i&gt; el resultado de la llamada a &lt;i&gt;Interlocked.Increment&lt;/i&gt;, en vez de desperdigar la llamada y la asignación entre dos instrucciones; enseguida veremos por qué. En caso de que no existiese &lt;i&gt;Interlocked&lt;/i&gt;, la forma correcta de realizar esta operación sería:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;public&lt;/b&gt; Cosa()&lt;br /&gt;{&lt;br /&gt;    &lt;b&gt;lock&lt;/b&gt; (&lt;b&gt;typeof&lt;/b&gt;(&lt;font color="darkcyan"&gt;Cosa&lt;/font&gt;))&lt;br /&gt;        instanceId = ++staticId;&lt;br /&gt;}&lt;/pre&gt;&lt;div&gt;Los más puristas verán con malos ojos el bloqueo sobre el &lt;b&gt;typeof&lt;/b&gt;, pero lo he escrito así para abreviar. Pues bien: el código anterior es equivalente al código correcto. El motivo por el que usamos &lt;b&gt;lock&lt;/b&gt; es evitar que, entre la modificación de la variable global y la asignación de su valor en el campo de la instancia pueda cederse el control a otro hilo. Si esto ocurriese, podría ser que recibiésemos un valor duplicado en &lt;i&gt;instanceId&lt;/i&gt;. La clase &lt;i&gt;Interlocked&lt;/i&gt;, precisamente, nos garantiza que el incremento de la variable estática y la copia del valor correcto como valor de retorno tengan lugar de forma atómica, sin posibilidad de que otro hilo pueda acceder a la variable estática modificada. La llamada a &lt;i&gt;Increment&lt;/i&gt;, por otra parte, es mucho más eficiente que el uso de &lt;b&gt;lock&lt;/b&gt;.&lt;/div&gt;&lt;div&gt;Por el contrario, en el código erróneo original, el "genio" ha roto la atomicidad de la operación... por no tomarse la molestia de examinar bien la documentación o meditar sobre el problema. ¿Cuándo se manifestó el error? Esta es la parte que suele infundir horror en los corazones sensibles: el error fue detectado casi por casualidad:&lt;/div&gt;&lt;ul type="disc"&gt;&lt;li&gt;Por una parte, para que se produzca el error, tienen que intercalarse las operaciones de dos hilos de manera muy especial. Estos problemas no se detectan con una simple ejecución... si no hay suerte.&lt;/li&gt;&lt;li&gt;Para rematar, y esto es tan grave como todo lo anterior, la aplicación tenía un sistema de "manejo" de errores demencial, que se tragaba todas las excepciones gracias a cantidades industriales de instrucciones &lt;b&gt;try&lt;/b&gt;/&lt;b&gt;catch&lt;/b&gt; repartidas uniformemente a lo largo y ancho del código. En caso de producirse un error, la aplicación se lo callaba taimadamente.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Un buen día, fue necesario sacar una copia de la colección de "cosas" en un &lt;i&gt;dataset&lt;/i&gt; vulgar y corriente... y ahí fue que saltó la violación de la unicidad.&lt;/div&gt;&lt;div&gt;Y usted quizás se pregunte si mi personaje imaginario (¡porque cualquier parecido con la realidad... ya sabe!) se merece que lo vapulee de este modo. Pues sí, se lo merece. En este caso, el resultado de su metedura de pata es que, en ocasiones, la aplicación veía muertos y perdía registros fantasmas. Nada grave: sólo se trataba de dinero. Imagine, en cambio, que la aplicación controlase aviones, o trenes de pasajeros, o que monitorizase constantes vitales en un hospital. ¡Todos a la cárcel! Hace mucho, migrando una aplicación de altas hospitalarias desde dBase a InterBase, tropecé con el expediente médico de un caballero al que habían, aparentemente, operado de los ovarios. En realidad, por un error parecido, la clave primaria del expediente de este señor coincidía con la clave del expediente de una mujer, y los registros de detalles eran compartidos por ambos expedientes.&lt;/div&gt;&lt;div&gt;Moraleja: las optimizaciones son buenas. Pero, ¡por favor!, léase bien el manual antes de experimentar con métodos que no conoce.&lt;/div&gt;&lt;hr class="p"&gt;&lt;div style="font-size: 85%; font-style: italic;"&gt;Vea también: &lt;a href="http://commanet.blogspot.com/2008/03/ms-ligero-que-un-bloqueo.html"&gt;Más ligero que un bloqueo&lt;/a&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-8394585479637146413?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/8394585479637146413/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=8394585479637146413&amp;isPopup=true' title='9 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/8394585479637146413'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/8394585479637146413'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/11/antologa-del-disparate-i.html' title='Antología del Disparate - I'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_QWaXq7W8dVI/SRiomksDoKI/AAAAAAAAAJY/rDlD-BURq-Q/s72-c/lock.png' height='72' width='72'/><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-7457446504515173090</id><published>2008-11-02T19:48:00.008+01:00</published><updated>2008-11-02T20:21:01.079+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='bases de datos'/><title type='text'>¡Cuidado con el Entity Framework!</title><content type='html'>&lt;div&gt;&lt;img style="float:right; margin:1px 0 1px 8px;border-style:none;padding:0px;" src="http://2.bp.blogspot.com/_QWaXq7W8dVI/SQ373ffJsfI/AAAAAAAAAJI/bhJYTMTvnes/s320/dracones.jpg" border="0" alt="Aquí hay dragones, y manías sacadas de Java, que es peor..." /&gt;&lt;span class="first"&gt;Una advertencia rápida:&lt;/span&gt; he recibido unos cuantos correos de programadores que quieren empezar proyectos con el ADO.NET Entity Framework, un añadido tardío del SP1 de Visual Studio 2008. Esta semana iré respondiendo todo el correo atrasado que tengo, pero prefiero ir adelantando aquí mi opinión.&lt;/div&gt;&lt;div&gt;Y mi opinión es que el Entity Framework (EF, en lo sucesivo) está demasiado verde. La versión del SP1, es cierto, está muy adelantada con respecto a las versiones liberadas durante las betas... pero eso es ya un síntoma de la fase actual del proyecto. En concreto, ¿cuáles son mis pegas?&lt;/div&gt;&lt;ol&gt;&lt;li&gt;La principal: fallos de estabilidad. Puede que sea un problema de mi sistema, pero me he encontrado con errores al realizar operaciones tan simples como añadir una nueva tabla a un modelo ya existente. Me he encontrado de repente con tres errores en el código generado (relacionados con las "asociaciones", es decir, las claves externas). Al eliminar la tabla nueva y la tabla con la que se relaciona, me he encontrado en la extraña situación de que ninguna de las dos tablas vuelve a aparecer en el esquema relacional de la base de datos (pero sí aparecen en el Server Explorer y en SQL Server Management Studio).&lt;/li&gt;&lt;li&gt;Creo que, por razones "ideológicas", se han dejado funcionalidad importante fuera. En concreto, el atributo &lt;b&gt;identity&lt;/b&gt; de SQL Server es como si no existiese. Para crear una "entidad" cuya clave es autoincremental, disponemos de un constructor sin parámetros... y de un método estático que obliga a pasar un valor explícito para la clave.&lt;/li&gt;&lt;li&gt;En realidad, detalles entrañables como el anterior son puntos del diseño, no una omisión o un descuido: los javalíes exigen que sus ORMs generen el código mínimo, y esas "chorradas" de claves automáticas entran en la categoría &lt;i&gt;Prescindible&lt;/i&gt; para esta gente. Bien, me parece estupendo... pero queda usted avisado de lo que encontrará.&lt;/li&gt;&lt;li&gt;Tenga &lt;b&gt;muy&lt;/b&gt; presente que el EF debe funcionar con SQL Server, Oracle y lo que se presente. Eso puede ser una ventaja para determinadas aplicaciones. Pero para quien vaya a trabajar directamente con SQL Server, es más un problema que otra cosa. Ya le he dicho que se ignoran las identidades. Resulta que también se ignoran las columnas &lt;b&gt;rowversion&lt;/b&gt;, que son la clave para acelerar el trabajo con la concurrencia optimista en SQL Server.&lt;/li&gt;&lt;li&gt;La documentación es un asco. Lo siento, "asco" es la palabra exacta. De momento, hay que irse a Internet, y el individuo que ha creado la ayuda es un sádico que ha repartido cada bit de información útil entre cincuenta páginas diferentes, con el único propósito de hacerle sufrir. No hay libros sobre este tema: hay anunciado uno de David Sceppa en Amazon... para el 2010. Espero que el mío esté muchísimo antes. Ah, sí, hay vídeos en inglés, pero tardas una hora de metraje en enterarte de lo que podrías leer en cinco minutos. Una de las razones por la que los vídeos siguen siendo solamente "material de apoyo" en mis cursos a distancia.&lt;/li&gt;&lt;li&gt;No tengo aún experiencia de primera mano en cómo funciona un sistema en tres capas basado en este invento. Es cierto que hay ahora un nuevo tipo de "ADO.NET Data Services", basado en HTTP. No sé cuán rápido puede ser este sistema para aplicaciones que necesitan verdaderamente rapidez y escalabilidad. Y a juzgar por lo que he visto, y por las experiencias con las tres capas en LINQ for SQL, me temo lo peor. Pero repito: todavía no he llegado a tanto.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;Resumiendo, no lo veo muy claro. No es una opinión definitiva, pues como es natural, todavía me falta soltura con la herramienta. Puede que dentro de tres meses me parezca una maravilla. Mi consejo, para que no me malinterprete, es: sea prudente. En los mapas antiguos, en las zonas inexploradas se colocaban advertencias como &lt;i&gt;Hic sunt dracones&lt;/i&gt;. Algún animal extraño nada en las ignotas aguas del ADO.NET Entity Framework. Puede terminar resultando un dragón, una sirena o un inofensivo calamar gigante.&lt;/div&gt;&lt;hr class="p"&gt;&lt;div&gt;&lt;span class="first"&gt;... y para que se haga&lt;/span&gt; una idea de cómo bajan las aguas, eche un vistazo a este documento:&lt;/div&gt;&lt;ul type="square"&gt;&lt;li&gt;&lt;a href="http://efvote.wufoo.com/forms/ado-net-entity-framework-vote-of-no-confidence/" target="_blank"&gt;Voto de reprobación&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Le advierto que las críticas vienen, en este caso, del lado oscuro de la Fuerza (es decir, de los javalíes).&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-7457446504515173090?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/7457446504515173090/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=7457446504515173090&amp;isPopup=true' title='31 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7457446504515173090'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7457446504515173090'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/11/cuidado-con-el-entity-framework.html' title='¡Cuidado con el Entity Framework!'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_QWaXq7W8dVI/SQ373ffJsfI/AAAAAAAAAJI/bhJYTMTvnes/s72-c/dracones.jpg' height='72' width='72'/><thr:total>31</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-1411982737079561909</id><published>2008-11-01T17:59:00.001+01:00</published><updated>2008-12-11T09:01:30.723+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='metodología'/><title type='text'>El escarabajo pelotero</title><content type='html'>&lt;h3&gt;Serie: Los N Pecados Capitales&lt;/h3&gt;&lt;div class="p"&gt;&lt;img style="float:right; margin:1px 0 1px 8px;border-style:none;padding:0px;" src="http://2.bp.blogspot.com/_QWaXq7W8dVI/SBSh6kf5faI/AAAAAAAAAIo/Ahe_5ZhGlhc/s320/dung.jpg" border="0" alt="El Escarabajo Pelotero de Mierda" /&gt;&lt;span class="first"&gt;Algunos sostienen que&lt;/span&gt; fue Aldous Huxley; la mayoría cree que fue J.B.S. Haldane, pero es también posible que se trate de una anécdota apócrifa. Cuentan que un teólogo victoriano preguntó a Haldane, biólogo de profesión, si podía deducir algo sobre Dios a partir de su huella en el Universo. La respuesta fue: "no sé, quizás una desmedida afición por los escarabajos".&lt;/div&gt;&lt;div class="p"&gt;Puede que Dios ame a los escarabajos, pero lo que es seguro es que algunos escarabajos han sido adorados como dioses. El escarabajo pelotero (&lt;i&gt;Scarabaeus sacer&lt;/i&gt;) es una especie de cucaracha acorazada que se pasa el día entero recogiendo mierda y amasándola en forma de pelotitas. Es un verdadero comemierdas, porque se alimenta de esa misma materia prima, e incluso deposita sus huevos dentro de las bolas de estiércol para su incubación.&lt;/div&gt;&lt;div class="p"&gt;Los egipcios, que para algunas cosas había que darles de comer aparte, observaron a los pequeños escarabajillos saliendo de su incubadora de mierda y dedujeron, los muy listos, que el bicho se autoenterraba en porquería para luego renacer, como ave fénix... aunque algo más pringada. Compararon la faena cotidiana del escarabajo, arrastrando bolitas de caca, con la sagrada misión de Ra, el dios encargado del disco solar. Y añadieron este bicho de mierda a su interminable lista de dioses, diosecillos y otros seres espirituales.&lt;/div&gt;&lt;div class="p"&gt;Más tarde, cuando el cristianismo llegó a Egipto, los coptos, que no andaban muy finos con esto de las metáforas, vieron en el escarabajo un símil anticipatorio del sacrificio de Cristo. En algunos libros de la época, se llega a llamar a Cristo el &lt;a href="http://encyclopedie-es.snyke.com/articles/escarabajo.html" target="_blank"&gt;&lt;i&gt;"bonus scarabaeus"&lt;/i&gt;&lt;/a&gt;: el buen escarabajo. Esto es lo que yo llamo una metáfora de mierda...&lt;/div&gt;&lt;hr class="p"&gt;&lt;div class="p"&gt;En Informática, un &lt;i&gt;escarabajo pelotero&lt;/i&gt; es el desgraciado que cree que las aplicaciones se escriben acumulando minúsculas pelotitas de mierda, una sobre la otra, de manera progresiva, a la vez que se canta una alegre canción. Hay escarabajos, no obstante, que creen que lo de la canción es opcional. Les va más el chasquido del látigo.&lt;/div&gt;&lt;div&gt;Un buen escarabajo pelotero es un individuo "constructivo", en el peor de los sentidos. ¿Hay que ordenar una lista? Fácil, se dice el insecto. Planta sus pezuñas sobre el primer elemento, y busca el menor de los restantes elementos. Si es diferente del primero, intercambia ambos. Luego pasa al siguiente elemento y repite el algoritmo. ¿Funciona? ¡Pues claro que funciona! Y es que he elegido al ejemplar más inteligente de la especie a la vez que el algoritmo más sencillo. El problema es que nuestro insecto ignora que existe una técnica llamada &lt;a href="http://es.wikipedia.org/wiki/Quicksort" target="_blank"&gt;quicksort&lt;/a&gt;, y que a partir de cierto tamaño, su uso se convierte en una necesidad. De manera que ya podemos identificar uno de los síntomas del trastorno:&lt;/div&gt;&lt;ul type="disc"&gt;&lt;li&gt;Pobre pensamiento algorítmico&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Ahí está el verdadero problema: no se trata de desconocer la existencia de un algoritmo dado, sino de la arrogancia que a veces, por desgracia, viene aparejada con el desconocimiento. Y si un escarabajo se permite ignorar la Algorítmica, no se le ocurra hablarle de estructuras de datos.&lt;/div&gt;&lt;div&gt;El daño que puede causar este angelito depende de lo alto que se encuentre en la jerarquía de una empresa. Imaginémoslo jefe de un proyecto que comienza. ¿Cómo lo haría? La necesidad de resultados inmediatos podría con él... y se lanzaría a rodar bolitas de mierdas, sin importar que el montón de bolitas se parezca más a una pirámide que al castillo que tiene que construir. Ya se encargarán los de &lt;i&gt;marketing&lt;/i&gt; de colgar un gran cartel a la entrada de la pirámide que diga: "CASTILLO".&lt;/div&gt;&lt;div&gt;Pero lo peor es que nuestro sujeto es ahora un jefecillo, y ya no tiene que ensuciarse las manos en mierda, porque para eso tiene su equipo. Este es el resultado:&lt;/div&gt;&lt;ul type="disc"&gt;&lt;li&gt;Un ciego, para dirigir a videntes, les obligará a vendarse los ojos&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Mientras menos información suministre a su equipo, el buen señor se sentirá más seguro. Nadie podrá darse cuenta a tiempo de su ineptitud. Y si la pirámide de bolitas de mierda se derrumba, la culpa siempre será los esclavos.&lt;/div&gt;&lt;div&gt;¿Tiene arreglo un escarabajo pelotero? Todo depende de cuán alto haya logrado reptar. Si el individuo está bajo su mando, hay una sencilla solución: cree un ambiente laboral intelectualmente estimulante. Organice seminarios internos, y haga rotar al ponente. Traiga revistas técnicas y libros a la oficina. El amor propio obra milagros.&lt;/div&gt;&lt;div&gt;Por el contrario, si el escarabajo está o estará por encima de usted en la jerarquía de mando, sobre todo si tiene potestad para interferir en su trabajo... huya. A esas alturas, el buen señor estará convencido de que ha llegado a su posición gracias, precisamente, a lo que él considera sus virtudes (ver el &lt;a href="http://en.wikipedia.org/wiki/Peter_principle" target="_blank"&gt;Principio de Peter&lt;/a&gt;), y cualquiera que contradiga su estilo, será visto como un enemigo peligroso. Váyase. Déje que su pirámide de estiércol se derrumbe sobre su cabeza. Ya se las apañará para renacer de entre la caca.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-1411982737079561909?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/1411982737079561909/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=1411982737079561909&amp;isPopup=true' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/1411982737079561909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/1411982737079561909'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/11/el-escarabajo-pelotero.html' title='El escarabajo pelotero'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_QWaXq7W8dVI/SBSh6kf5faI/AAAAAAAAAIo/Ahe_5ZhGlhc/s72-c/dung.jpg' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-5013101093993912888</id><published>2008-04-26T20:21:00.007+02:00</published><updated>2008-12-11T09:01:30.917+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cargocultismo'/><category scheme='http://www.blogger.com/atom/ns#' term='metodología'/><title type='text'>Cargocultismo</title><content type='html'>&lt;h3&gt;Serie: Los N Pecados Capitales&lt;/h3&gt;&lt;div class="p"&gt;&lt;span class="first"&gt;Durante la Segunda Guerra Mundial&lt;/span&gt;, las tropas americanas desembarcaron en muchas islas cuyos habitantes habían tenido poco o ningún contacto con la civilización occidental. Ante los ojos de estos nativos, se desarrollaba un drama sacado de la ciencia ficción: unos seres curiosos, venidos de muy lejos, que realizaban ceremonias incomprensibles, a través de las cuales obtenían un nivel de bienestar material antes desconocido en la zona.&lt;/div&gt;&lt;div class="p"&gt;&lt;img style="float:right; margin:1px 0 1px 8px;border-style:none;padding:0px;" src="http://2.bp.blogspot.com/_QWaXq7W8dVI/SAoUchevdTI/AAAAAAAAAIg/BvgRT30yHYo/s320/cargocultism.jpg" border="0" alt="Marcha del Día de John Frumm" /&gt;Uno de aquellos seres, por ejemplo, pasaba horas hablando con una extraña caja de la que sobresalían cuerdas de metal. Al parecer, aquellas conversaciones con la misteriosa caja conseguían que en la isla se posaran gigantescos pájaros de hierro, procedentes de la tierra de los antepasados, de cuyos vientres se extraían toneladas de comida, armas y otros objetos deslumbrantes y probablemente útiles. No, no se trataba de dioses, pero era evidente que aquella tribu había descubierto cómo contactar con sus antepasados y recibir la correspondiente bendición material.&lt;/div&gt;&lt;div class="p"&gt;Llamaba también la atención el que buena parte de estos marines fuesen de piel oscura... como la mayoría de los nativos, pues he olvidado aclarar que mi historia tuvo lugar en la Melanesia. Esto hacía que la idea de contactar con los antepasados para recibir un cargamento resultase más creíble: los negros de aquella tribu lo habían logrado, ¿no? En la mente de estos melanesios comenzó a forjarse la image de un tal John Frumm (¿John from America, quizás?) un marine negro que prometía volver para ayudar a los nativos tras la guerra.&lt;/div&gt;&lt;div class="p"&gt;Naturalmente, terminó la guerra y John Frumm no regresó. O si regresó, no lo reconocieron. Ante la ausencia, ¿por qué no intentar seguir el camino de Frumm? Tallaron radios de madera de cocotero, y pintaron líneas con hollín sobre zonas despejadas. Nativos con hojas de palmeras en sus manos imitaban el código de banderas de los norteamericanos, con la esperanza que aquel baile que habían visto ejecutar a John Frumm atrajese el cargamento de los antepasados a las islas.&lt;/div&gt;&lt;div class="p"&gt;Aún hoy, "tropas" de melanesios desharrapados desfilan en algunas islas con rifles de madera al hombro. El fenómeno se conoce como &lt;i&gt;cargo cult&lt;/i&gt; y, como puede sospechar, ha sufrido algunos cambios en su necesaria evolución. Por ejemplo, para algunas sectas, los blancos se oponen a revelar el secreto del "cargo", y periódicamente estalla la violencia contra los pocos occidentales que tienen a mano. Ha surgido también algún mesías nativo que ha reclamado ser un avatar de John Frumm, y ha propiciado el correspondiente cisma entre los cultocarguistas.&lt;/div&gt;&lt;hr class="p"&gt;&lt;div class="p"&gt;La Informática está llena de cargocultistas: personas que han visto a otras usar con éxito determinada técnica, y que luego se lanzan a repetir la ceremonia sin entender realmente de qué se trata. Por ejemplo, todo el mundo ha leído sobre la maravillosa revolución que se produjo cuando Santa Programación Orientada a Objetos se encarnó entre los mortales, allá por los tiempos de gloria de C++. Por lo tanto, cuando es necesario escribir una aplicación para bases de datos, intentan utilizar eso de los "objetos". Y establecen principios como: &lt;i&gt;"sólo es profesional aquel que define una clase Cliente"&lt;/i&gt;. O: &lt;i&gt;"tenemos que usar UML,  o Java, o servicios Web... aunque no tengamos ni puñetera idea de por qué, pues es lo que hacen los programadores serios"&lt;/i&gt;. Amén, hermano.&lt;/div&gt;&lt;div class="p"&gt;Observe que el cargocultismo es un mal diferente del &lt;a href="http://commanet.blogspot.com/2008/04/el-pollo-de-skinner.html"&gt;síndrome del pollo de Skinner&lt;/a&gt;. En este último, se cree en la existencia de una relación causa/efecto inexistente, mientras que el cargocultismo se basa en una conexión real, que verdaderamente funciona... excepto que el cargocultista no comprende por qué. ¿Otra diferencia? Nadie confesaría voluntariamente que actúa como un pollo de Skinner, mientras que el cargocultismo tiene cierta aura de respetabilidad a su alrededor. Cuestione a un cargocultista, y parecerá que está cuestionando los principios más básicos de la profesión.&lt;/div&gt;&lt;div class="p"&gt;Además, tengo mejor opinión de un pollo de Skinner que de un cultocarguista. En cierto modo, todos hemos sido pollos de Skinner: el aprendizaje y la experiencia son la medicina contra ese estado. Por el contrario, es difícil curar a un cargocultista.&lt;/div&gt;&lt;div class="p"&gt;Y es que, en este mundo, mucha gente sigue esperando el regreso de John Frumm.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-5013101093993912888?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/5013101093993912888/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=5013101093993912888&amp;isPopup=true' title='15 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/5013101093993912888'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/5013101093993912888'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/04/cargocultismo_26.html' title='Cargocultismo'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_QWaXq7W8dVI/SAoUchevdTI/AAAAAAAAAIg/BvgRT30yHYo/s72-c/cargocultism.jpg' height='72' width='72'/><thr:total>15</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-1014155389681057383</id><published>2008-04-19T13:09:00.026+02:00</published><updated>2010-08-31T11:52:41.485+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='metodología'/><title type='text'>El Pollo de Skinner</title><content type='html'>&lt;h3&gt;Serie: Los N Pecados Capitales&lt;/h3&gt;&lt;div class="p"&gt;&lt;span class="first"&gt;Burrhus F. Skinner fue un&lt;/span&gt; famoso psicólogo estadounidense, mundialmente conocido por sus trabajos en la escuela &lt;i&gt;conductista&lt;/i&gt;; aparte de lo anterior, y sin menoscabo de lo dicho, fue también un redomado cabrón (y que me perdonen sus descendientes y herederos). No es éste el momento de explicar el adjetivo, sin embargo. Sólo quiero contar uno de sus muchos experimentos.&lt;/div&gt;&lt;div class="p"&gt;&lt;img style="float:right; margin:1px 0 1px 8px;border-style:none;padding: 0px;" src="http://1.bp.blogspot.com/_QWaXq7W8dVI/SAoLqRevdSI/AAAAAAAAAIY/1dq-Q0DTcDY/s320/dchick.jpg" border="0" alt="La Danza del Pollo de Skinner" /&gt;Skinner puso un pollo frente a una caja que, de manera totalmente aleatoria, recompensaba al animalito, de cuando en cuando, con una golosina. El minúsculo cerebro del ave, no obstante, intentaba establecer una relación causa/efecto entre sus acciones y las recompensas. Si los pollos hablasen, ésta sería una posible transcripción de sus pensamientos:&lt;/div&gt;&lt;div class="p" style="margin-left:24px;margin-right:24px;font-style:italic;font-size: 90%;line-height:120%;"&gt;¡Vaya, se ha abierto la caja! ¡Y qué gusano más sabroso había dentro! Veamos, ¿qué estaba haciendo cuando se abrió la caja? Entonces movía el cuello, de arriba a abajo. Repitámoslo. Arriba. Abajo... Nada, recórcholis... ¡espera, se vuelve a abrir! Gulp... Parece que si levanto una pata en el segundo movimiento, funciona. Ahí vamos... Espera, debo haberlo hecho mal. Corrijamos el movimiento de la cola... ¡Abrete, maldita seas!&lt;/div&gt;&lt;div class="p"&gt;Los pollos de Skinner terminaban elaborando complicadas danzas con el propósito de influir en la apertura de la caja de las golosinas. A pesar de todo, la caja se abría por motivos completamente distintos...&lt;/div&gt;&lt;hr class="p"&gt;&lt;div class="p"&gt;Muchos programadores y analistas se comportan como los pollos de Skinner. Se enfrentan a sistemas complicados, cuyo funcionamiento no conocen a fondo. Tras mil peripecias, logran que la aplicación funcione, pero atribuyen la causa del correcto funcionamiento a factores equivocados. Y el toque de brujería termina transformándose en un Principio, con mayúsculas, que todo recién llegado debe acatar, so pena de terribles torturas.&lt;/div&gt;&lt;div class="p"&gt;¿A santo de qué cuento esta historia? No sea mal pensado: estaba recordando algunos casos pintorescos que he conocido como consultor, y se me ocurrió recopilar algunos de los patrones, o más bien &lt;i&gt;antipatrones&lt;/i&gt;, que son frecuentes en este mundillo. El primer antipatrón que me ha venido a la mente es el del Pollo de Skinner. Pero habrá más...&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-1014155389681057383?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/1014155389681057383/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=1014155389681057383&amp;isPopup=true' title='10 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/1014155389681057383'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/1014155389681057383'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/04/el-pollo-de-skinner.html' title='El Pollo de Skinner'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_QWaXq7W8dVI/SAoLqRevdSI/AAAAAAAAAIY/1dq-Q0DTcDY/s72-c/dchick.jpg' height='72' width='72'/><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-1199966596826031074</id><published>2008-04-13T22:23:00.010+02:00</published><updated>2008-04-13T23:04:20.252+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='óptica'/><category scheme='http://www.blogger.com/atom/ns#' term='ray tracing'/><title type='text'>Espectros</title><content type='html'>&lt;div class="p"&gt;&lt;span class="first"&gt;La ley de Beer establece&lt;/span&gt; que un rayo de luz se atenúa exponencialmente al atravesar un material dieléctrico, como el vidrio. Esta ley es necesaria para reproducir materiales transparentes coloreados, como en la siguiente imagen, que copio del post anterior:&lt;/div&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;" src="http://www.marteens.com/xsight/images/glass320.png" border="0" alt="Refracción y ley de Beer" /&gt;&lt;div class="p"&gt;La mayoría de los ray tracers, XSight RT incluido, implementan la ley de Beer asociando un filtro a estos materiales. El código correspondiente, en XSight RT, está ubicado dentro del método &lt;i&gt;Trace&lt;/i&gt; que heredan todos los &lt;i&gt;samplers&lt;/i&gt; del motor:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;if&lt;/b&gt; (attenuation)&lt;br /&gt;{&lt;br /&gt;   &lt;font color="darkgreen"&gt;&lt;i&gt;// Exponential attenuation inside transparent media.&lt;/i&gt;&lt;/font&gt;&lt;br /&gt;   filter.blue *= (&lt;b&gt;float&lt;/b&gt;)&lt;font color="teal"&gt;Math&lt;/font&gt;.Exp(attFltr.blue * info.Time);&lt;br /&gt;   filter.green *= (&lt;b&gt;float&lt;/b&gt;)&lt;font color="teal"&gt;Math&lt;/font&gt;.Exp(attFltr.green * info.Time);&lt;br /&gt;   filter.red *= (&lt;b&gt;float&lt;/b&gt;)&lt;font color="teal"&gt;Math&lt;/font&gt;.Exp(attFltr.red * info.Time);&lt;br /&gt;}&lt;/pre&gt;&lt;div class="p"&gt;Esta parece ser la extrapolación más "natural" de la ley de Beer para que se pueda aplicar a luz multicromática. Sin embargo, es fácil darse cuenta del problema que crea esta implementación. Para intervalos pequeños, es posible controlar los parámetros para dar con cualquier color deseado para el vidrio. Para intervalos grandes, sin embargo, cualquier componente del filtro de atenuación que sea menor que la unidad, terminará eliminando completamente el correspondiente canal de color de la imagen.&lt;/div&gt;&lt;div class="p"&gt;Por ejemplo, si digo que mi material tiene un filtro de atenuación con componentes &lt;i&gt;1, 0, 0&lt;/i&gt; (para el rojo, verde y azul), estaré consiguiendo un vidrio rojo. Si cambio el filtro a &lt;i&gt;1, 0.5, 0&lt;/i&gt;, lograré que los objetos delgados de este material sean de color naranja... pero para objetos más gruesos, la luz terminará atenuándose hacia el rojo puro.&lt;/div&gt;&lt;div&gt;¿Es esto un comportamiento "natural"? Evidentemente no, sino que se trata de un comportamiento inducido por la implementación de los colores en el ray tracer. Esto me ha llevado a investigar, por simple curiosidad, sobre cómo podría implementarse un ray tracer que trabajase con píxeles de cuatro, cinco o más canales espectrales. Hay, sin embargo, muy poca documentación sobre este asunto, aunque me consta que algunos programas comerciales implementan recursos parecidos. Si usted sabe algo sobre el tema, le agradecería cualquier pista.&lt;/div&gt;&lt;hr class="p"&gt;&lt;div class="p"&gt;... y se me ocurre otra idea: buena parte del código consiste en instrucciones por triplicado que manipulan los tres componentes básicos de color de un píxel. ¿Sería posible idear una representación diferente del color que simplificase estos cálculos? Por ejemplo, ¿tiene algún sentido el ray tracing con colores en el espacio HSV? ¿Simplificaría el código? ¿Lo haría más eficiente? De momento, es una pregunta abierta...&lt;/div&gt;&lt;hr class="p"&gt;&lt;div class="p"&gt;Para terminar, una curiosidad: a primera vista, es lógico pensar que una esfera de cristal tintado debería mostrar un tono mucho más claro en los bordes, en comparación con su centro, ya que en los bordes el camino a recorrer sería menor, y se produciría menos atenuación. Sin embargo, esto no ocurre así, y puede buscar una esfera "real" de cristal para comprobarlo.&lt;/div&gt;&lt;div class="p"&gt;¿Por qué? Es sencillo: resulta que los rayos de luz que emergen en la zona cercana al borde viajan proporcionalmente un trayecto más largo de lo que pensamos, por culpa de las leyes de la refracción. De hecho, ocurre algo interesante e insospechado: hay una parte del interior de una esfera de cristal que, al mirarla de frente, no podemos ver, debido también a la refracción. Esto es fácil de comprobar generando imágenes de esferas de vídrio con esferas opacas más pequeñas en su interior. Es muy probable que este comportamiento se aproveche en algún truco de magia. Se lo preguntaré al espíritu de Houdini.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-1199966596826031074?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/1199966596826031074/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=1199966596826031074&amp;isPopup=true' title='17 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/1199966596826031074'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/1199966596826031074'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/04/espectros.html' title='Espectros'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>17</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-7475126064004690422</id><published>2008-04-09T00:19:00.005+02:00</published><updated>2008-12-11T09:01:31.282+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='XSight'/><title type='text'>XSight RT v1.5</title><content type='html'>&lt;div class="p"&gt;&lt;img style="float:right; margin:1px 0 1px 8px; border-style:none;padding:0px;" src="http://4.bp.blogspot.com/_QWaXq7W8dVI/R63wxYlrv3I/AAAAAAAAAHY/8_LA7rSwtvs/s320/csg.jpg" border="0" alt="" /&gt;&lt;span class="first"&gt;Nueva versión pública&lt;/span&gt; de &lt;a href="http://www.marteens.com/zips/XSightRT15.zip"&gt;XSight RT v1.5&lt;/a&gt;, también para .NET Framework 3.5. La descarga contiene el instalador del ejecutable, la ayuda y un puñado de escenas para pruebas. No he incluido el código fuente.&lt;/div&gt;&lt;div class="p"&gt;La aplicación permite editar escenas con un lenguaje sencillo y bien documentado, y generar imágenes a partir de estas descripciones. De momento, funciona como una aplicación SDI, permitiendo trabajar con un único documento por instancia de la misma.&lt;/div&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;" src="http://www.marteens.com/xsight/images/glass320.png" border="0" alt="Refracción y ley de Beer" /&gt;&lt;div class="p"&gt;En esta versión, se incorpora la generación concurrente de escenas, con un &lt;i&gt;modo dual&lt;/i&gt;, que reduce casi a la mitad el tiempo de generación en ordenadores con doble núcleo (algo menos en procesadores de un solo núcleo con &lt;i&gt;hyperthreading&lt;/i&gt;). Además, ya funciona el material &lt;i&gt;glass&lt;/i&gt;, y puede utilizarse un color para el cristal (según la ley de Beer). Hay también soporte para normales perturbadas, los pigmentos &lt;i&gt;crackle&lt;/i&gt; y &lt;i&gt;bubbles&lt;/i&gt;, cilindros y esferas de cuarto grado, una operación &lt;i&gt;merge&lt;/i&gt; para materiales transparentes (equivalente a &lt;i&gt;union&lt;/i&gt;, pero eliminando las superficies internas). Y se ha mejorado la velocidad, en general, del núcleo.&lt;/div&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;" src="http://www.marteens.com/xsight/images/puzzle320.png" border="0" alt="Reflexión difusa y niebla" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-7475126064004690422?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/7475126064004690422/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=7475126064004690422&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7475126064004690422'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7475126064004690422'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/04/xsight-rt-v15.html' title='XSight RT v1.5'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_QWaXq7W8dVI/R63wxYlrv3I/AAAAAAAAAHY/8_LA7rSwtvs/s72-c/csg.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-259899253488996006</id><published>2008-03-31T20:59:00.014+02:00</published><updated>2008-12-11T09:01:31.461+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bloqueos'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='hilos'/><title type='text'>Más ligero que un bloqueo</title><content type='html'>&lt;div class="p"&gt;&lt;img style="float:right; margin:1px 0 1px 8px;border-style:none;padding:0px;" src="http://2.bp.blogspot.com/_QWaXq7W8dVI/R_E9a37XufI/AAAAAAAAAII/y8f-IZkURmk/s320/feather.jpg" border="0" alt="" /&gt;&lt;span class="first"&gt;Seamos sinceros: si&lt;/span&gt; usted necesita un bloqueo, no va a conseguir un recurso menos costoso que el propio bloqueo. Ahora bien, es muy diferente si lo que usted necesita no es &lt;i&gt;exactamente&lt;/i&gt; un bloqueo, sino parte de la funcionalidad del bloqueo. En tal caso, hay alternativas.&lt;/div&gt;&lt;div class="p"&gt;Hace poco me encontré en esta situación, añadiendo concurrencia a XSight RT. En las últimas versiones (no publicadas todavía) dos hilos pueden ocuparse de una misma escena, generando bandas disjuntas sobre un mismo objeto &lt;i&gt;PixelMap&lt;/i&gt; (los mapas de bits internos del API de XSight RT). De este modo, los dos hilos pueden trabajar sin molestarse mutuamente. El conflicto se produce cuando hay que ejecutar un evento para avisar al cliente del API de que hay una banda nueva que se puede mostrar incrementalmente en la ventana de salida. En el código original, sin soporte de hilos, ésta era una tarea del &lt;i&gt;sampler&lt;/i&gt;. En el nuevo código, por inercia, este código se duplicó en cada hilo: cada uno intenta notificar al cliente, cuando se ha acumulado trabajo o ha pasado suficiente tiempo.&lt;/div&gt;&lt;div class="p"&gt;¿Primera solución? Proteger ese código mediante un bloqueo, por supuesto:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;if&lt;/b&gt; (SeDanLasCondiciones())&lt;br /&gt;   &lt;b&gt;lock&lt;/b&gt;&lt;br /&gt;   {&lt;br /&gt;      Avisar();&lt;br /&gt;   }&lt;/pre&gt;&lt;div class="p"&gt;Esto es matar gorriones a cañonazos. Un bloqueo, implementado aquí mediante la instrucción &lt;b&gt;lock&lt;/b&gt;, que el compilador traduce en llamadas a la clase &lt;i&gt;Monitor&lt;/i&gt;, se encarga en realidad de dos tareas que se pueden separar:&lt;/div&gt;&lt;ol&gt;&lt;li&gt;Comprobar que el código protegido no pueda ejecutarse simultáneamente por más de un hilo.&lt;/li&gt;&lt;li&gt;Si un hilo solicita el bloqueo mientras está concedido a otro hilo, el hilo se pone en modo de espera.&lt;/li&gt;&lt;/ol&gt;&lt;div class="p"&gt;Pasar al "modo de espera" puede ser costoso, de acuerdo a la técnica con la que se haya implementado el bloqueo. En el peor de los casos, si se suspende el hilo mediante llamadas al API de Windows, esto provoca un pequeño terremoto en el planificador de tareas: tenga presente que se produce una transición al modo &lt;i&gt;kernel&lt;/i&gt; del sistema operativo.&lt;/div&gt;&lt;div class="p"&gt;Para su tranquilidad, es muy poco probable que &lt;i&gt;Monitor&lt;/i&gt;, y por consiguiente la instrucción &lt;b&gt;lock&lt;/b&gt;, implemente la espera de esta manera. Lo más probable es que intente esperar un instante antes de tomar medidas drásticas y tomarse el somnífero.&lt;/div&gt;&lt;div class="p"&gt;No obstante, en mi ejemplo, ni siquiera hace falta esperar. ¿Que un hilo intenta notificar y encuentra que alguien se le ha adelantado? ¡Estupendo! ¡Ya no necesita notificar sobre nada! La única parte que necesitamos del bloqueo es la funcionalidad de exclusión mutua... y para esta tarea sencilla, existe un mejor mecanismo. Observe:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;private int&lt;/b&gt; access;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;public bool&lt;/b&gt; ReportProgress()&lt;br /&gt;{&lt;br /&gt;   &lt;b&gt;int&lt;/b&gt; elapsed = &lt;font color="teal"&gt;Environment&lt;/font&gt;.TickCount;&lt;br /&gt;   &lt;b&gt;if&lt;/b&gt; (elapsed - lastReport &gt; MIN_INTERVAL)&lt;br /&gt;   {&lt;br /&gt;&lt;div style="background-color: #eaeaea; margin:0px 24px 0px 0px; line-height:normal;"&gt;      &lt;b&gt;if&lt;/b&gt; (0 == &lt;font color="teal"&gt;Interlocked&lt;/font&gt;.Exchange(&lt;b&gt;ref&lt;/b&gt; access, 1))&lt;br /&gt;      {&lt;br /&gt;         lastReport = elapsed;&lt;br /&gt;         listener.Progress(progressInfo);&lt;br /&gt;         &lt;font color="teal"&gt;Interlocked&lt;/font&gt;.Exchange(&lt;b&gt;ref&lt;/b&gt; access, 0);&lt;br /&gt;      }&lt;/div&gt;      &lt;b&gt;return&lt;/b&gt; !progressInfo.CancellationPending;&lt;br /&gt;   }&lt;br /&gt;   &lt;b&gt;else&lt;br /&gt;      return true&lt;/b&gt;;&lt;br /&gt;}&lt;/pre&gt;&lt;div class="p"&gt;Este código está ubicado en la clase &lt;i&gt;Scene&lt;/i&gt;, y los dos hilos comparten una instancia de la misma. Por lo tanto, ambos hilos están usando el mismo campo &lt;i&gt;access&lt;/i&gt;, declarado dentro de &lt;i&gt;Scene&lt;/i&gt;. Este campo se utiliza en la zona resaltada del método, a través de métodos estáticos de la clase &lt;i&gt;Interlocked&lt;/i&gt;.&lt;/div&gt;&lt;div class="p"&gt;Primero se ejecuta el método &lt;i&gt;Exchange&lt;/i&gt;. Este método intercambia el valor almacenado en la variable con el valor que pasamos como parámetro, y nos devuelve el antiguo valor de la variable. Además, nos ofrece la garantía de que todo este meneo lo hará de forma &lt;i&gt;atómica&lt;/i&gt;: no se producirán intromisiones durante su ejecución. Nosotros asumiremos que el valor "normal" del campo &lt;i&gt;access&lt;/i&gt; es cero. ¿Qué pasa si intentamos intercambiar el cero por un uno, y descubrimos que ya tiene un uno? Simplemente, que alguien se nos ha adelantado. En tal caso, renunciamos a notificar, pues ya alguien se ha ocupado del asunto. De lo contrario, si &lt;i&gt;Exchange&lt;/i&gt; devuelve cero, tendremos la seguridad de que nadie más ejecutará la notificación... al menos, mientras no reasignemos un cero en &lt;i&gt;access&lt;/i&gt;. Esto es precisamente lo que hacemos al terminar con la notificación, dejando la vía libre para la próxima notificación.&lt;/div&gt;&lt;hr class="p"&gt;&lt;div style="font-size: 85%; font-style: italic;"&gt;Vea también: &lt;a href="http://commanet.blogspot.com/2008/11/antologa-del-disparate-i.html"&gt;Antología del disparate I&lt;/a&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-259899253488996006?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/259899253488996006/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=259899253488996006&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/259899253488996006'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/259899253488996006'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/03/ms-ligero-que-un-bloqueo.html' title='Más ligero que un bloqueo'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_QWaXq7W8dVI/R_E9a37XufI/AAAAAAAAAII/y8f-IZkURmk/s72-c/feather.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-4244435839189230107</id><published>2008-03-04T08:46:00.005+01:00</published><updated>2008-12-11T09:01:31.610+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='geometría'/><category scheme='http://www.blogger.com/atom/ns#' term='ray tracing'/><category scheme='http://www.blogger.com/atom/ns#' term='XSight'/><title type='text'>Superesferas</title><content type='html'>&lt;img style="display:block; margin:0px auto 10px; text-align:center;" src="http://3.bp.blogspot.com/_QWaXq7W8dVI/R8z-nDm8gAI/AAAAAAAAAH4/qHPZtKxJCUA/s320/die.png" border="0" alt="Superesferas (XSight RT)" /&gt;&lt;div class="p"&gt;&lt;span class="first"&gt;El dado de la imagen está&lt;/span&gt; modelado mediante una "superesfera" que se puede describir mediante la ecuación &lt;i&gt;x^4 + y^4 + z^4 = 1&lt;/i&gt;. Al tratarse de una ecuación de cuarto grado, se puede resolver algebraicamente, algo que XSight RT hace muy eficientemente. El resultado es la figura del dado: un objeto a mitad de camino entre una esfera (de las de toda la vida) y un cubo. Si en vez de elevar a la cuarta potencia, usásemos exponentes mayores, la figura iría aproximándose más al cubo... pero la ecuación dejaría de tener una solución algebraica, y tendría que resolverse mediante el &lt;a href="http://es.wikipedia.org/wiki/M%C3%A9todo_de_Newton" target="_blank"&gt;método de Newton&lt;/a&gt;.&lt;/div&gt;&lt;div class="p"&gt;Las texturas del tapete y del propio dado están modeladas, naturalmente, mediante el clásico y eficiente &lt;a href="http://mrl.nyu.edu/~perlin/doc/oscar.html" target="_blank"&gt;ruido de Perlin&lt;/a&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-4244435839189230107?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/4244435839189230107/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=4244435839189230107&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/4244435839189230107'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/4244435839189230107'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/03/superesferas.html' title='Superesferas'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_QWaXq7W8dVI/R8z-nDm8gAI/AAAAAAAAAH4/qHPZtKxJCUA/s72-c/die.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-2228270421164468679</id><published>2008-03-01T00:02:00.005+01:00</published><updated>2008-12-11T09:01:31.764+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ray tracing'/><category scheme='http://www.blogger.com/atom/ns#' term='XSight'/><title type='text'>Grietas</title><content type='html'>&lt;img style="display:block; margin:0px auto 10px; text-align:center;" src="http://2.bp.blogspot.com/_QWaXq7W8dVI/R8iPOrJVo3I/AAAAAAAAAHo/miirdMM8N4I/s1600/crackle.jpg" border="0" alt="Crackle" /&gt;&lt;div class="p"&gt;&lt;span class="first"&gt;Observe el cambio en&lt;/span&gt; el "suelo", respecto a la imagen del post anterior: he añadido un patrón que en inglés se conoce como &lt;i&gt;crackle&lt;/i&gt;. Lo interesante es que está basado en los diagramas de Voronoi, que se definen como el conjunto de líneas equidistantes respecto a un conjunto de puntos aleatorios en el plano. Si a un robot lo situas en una habitación con objetos calientes, para evitar acercarse demasiado a ellos, tendría que calcular el diagrama de Voronoi asociado, para moverse a lo largo de las líneas del mismo.&lt;/div&gt;&lt;div class="p"&gt;En mi imagen, se ha utilizado el &lt;i&gt;crackle&lt;/i&gt; para el "pigmento" del plano, pero podría utilizarse también para trucar los vectores normales, y simular que el plano está ligeramente arrugado. Esta técnica, aplicada a una superficie reflectante, puede usarse para simular la superficie del mar.&lt;/div&gt;&lt;div style="background-color: #c0c0c0; margin-left: 24px; margin-right: 24px; font-size: 85%; line-height:normal; font-style:italic;"&gt;&lt;div style="padding: 12px 16px 12px 32px;"&gt;Para una versión del I King&lt;br /&gt;J.L. Borges&lt;br /&gt;&lt;br /&gt;El porvenir es tan irrevocable&lt;br /&gt;Como el rígido ayer. No hay una cosa&lt;br /&gt;Que no sea una letra silenciosa&lt;br /&gt;De la eterna escritura indescifrable&lt;br /&gt;Cuyo libro es el tiempo. Quien se aleja&lt;br /&gt;De su casa ya ha vuelto. Nuestra vida&lt;br /&gt;Es la senda futura y recorrida.&lt;br /&gt;El rigor ha tejido la madeja.&lt;br /&gt;No te arredres. La ergástula es oscura,&lt;br /&gt;La firme trama es de incesante hierro,&lt;br /&gt;Pero en algún recodo de tu encierro&lt;br /&gt;Puede haber una luz, una hendidura.&lt;br /&gt;El camino es fatal como la flecha.&lt;br /&gt;Pero en las grietas está Dios, que acecha.&lt;/div&gt;&lt;/div&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;" src="http://4.bp.blogspot.com/_QWaXq7W8dVI/R8lGO7JVo4I/AAAAAAAAAHw/UOhpMNEs35E/s320/diffraction.jpg" border="0" alt="El patrón crackle, imitando la difracción de la luz entre las hojas de un árbol" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-2228270421164468679?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/2228270421164468679/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=2228270421164468679&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2228270421164468679'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2228270421164468679'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/03/grietas.html' title='Grietas'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_QWaXq7W8dVI/R8iPOrJVo3I/AAAAAAAAAHo/miirdMM8N4I/s72-c/crackle.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-1722830686540057504</id><published>2008-02-24T23:25:00.007+01:00</published><updated>2008-02-26T14:43:32.858+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ray tracing'/><category scheme='http://www.blogger.com/atom/ns#' term='XSight'/><title type='text'>Físicamente imposible</title><content type='html'>&lt;div class="p"&gt;&lt;span class="first"&gt;No es difícil&lt;/span&gt; verlo: ¿qué es lo que "falla" en la siguiente imagen?&lt;/div&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;" src="http://www.marteens.com/xsight/images/def_glass.png" border="0" alt="Dos esferas de cristal (XSight RT)" /&gt;&lt;div class="p"&gt;No se trata de la distorsión de los mosaicos: la imagen ha sido generada con una lente cilíndrica. Este tipo de lentes permite representar ángulos mayores en una de las dos dimensiones (alto/ancho), al precio de que las líneas rectas no siempre se representan como líneas rectas en la imagen generada.&lt;/div&gt;&lt;hr class="p"&gt;&lt;div class="p"&gt;&lt;span class="first"&gt;El problema está,&lt;/span&gt; en efecto, en la sombra bajo las esferas. Pero no se trata de que sobren las sombras... sino de que falta algo dentro de las sombras: el área donde se concentran los rayos por el efecto lenticular de las esferas. Es una paradoja: se puede lograr sombra con una esfera transparente.&lt;/div&gt;&lt;div class="p"&gt;La imagen ha sido generada, por supuesto, con &lt;a href="http://www.marteens.com/xsight"&gt;XSight RT&lt;/a&gt;, y se trata de una prueba del nuevo soporte para refracción. La buena noticia: la simulación de materiales es buena. Me gusta más la apariencia del "vidrio" (la mezcla de reflexión y refracción dependiente del ángulo de incidencia) de XSight RT que la de POV Ray, al menos en el vidrio que éste ofrece por omisión. Además, no se pierde velocidad relativa.&lt;/div&gt;&lt;div class="p"&gt;&lt;img style="float:left; margin:1px 8px 1px 0px;" src="http://www.marteens.com/xsight/images/caustics.jpg" border="0" alt="Imagen generada con POV Ray" /&gt;¿Cómo habría que resolver lo de la sombra? POV Ray ofrece varias salidas: la primera, que fue probablemente la primera en soportar históricamente, consiste en tener en cuenta la presencia de materiales transparentes al efectuar las pruebas de oclusión. Es decir, se podría permitir que la luz directa atravesase la esfera. XSight RT no seguirá esa vía... porque también es físicamente incorrecta. El problema es que el algoritmo &lt;i&gt;puro&lt;/i&gt; de raytracing no permite generar las superficies cáusticas. El raytracing consiste en generar los rayos a la inversa, partiendo de la cámara, y aquí hace falta trazar rayos directamente desde una fuente de luz.&lt;/div&gt;&lt;div class="p"&gt;La segunda solución de POV Ray, y que será la implementada por XSight RT, es utilizar una técnica llamada &lt;a href="http://graphics.ucsd.edu/~henrik/papers/photon_map/" target="_blank"&gt;photon mapping&lt;/a&gt;. El reto está en hacerlo eficientemente, y que la técnica sea lo más "transparente" posible para el diseñador gráfico. Quiero decir, que no sea necesario indicar tropecientos parámetros para poder generar este tipo de imágenes.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-1722830686540057504?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/1722830686540057504/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=1722830686540057504&amp;isPopup=true' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/1722830686540057504'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/1722830686540057504'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/02/fsicamente-imposible.html' title='Físicamente imposible'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-889828936085444606</id><published>2008-02-19T09:53:00.022+01:00</published><updated>2008-12-11T09:01:31.944+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ray tracing'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>Recursividad anónima</title><content type='html'>&lt;div class="p"&gt;&lt;span class="first"&gt;... y hablando de raytracing&lt;/span&gt;, aquí tiene uno bastante exótico, planteado como una gigantesca consulta LINQ en C&lt;sup&gt;#&lt;/sup&gt; 3.0:&lt;/div&gt;&lt;ul type="square"&gt;&lt;li&gt;&lt;a href="http://blogs.msdn.com/lukeh/archive/2007/10/01/taking-linq-to-objects-to-extremes-a-fully-linqified-raytracer.aspx" target="_blank" title="Taking LINQ to Objects to extremes"&gt;A Fully LINQified Ray Tracer&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="p"&gt;&lt;img style="float:right; margin:1px 0 1px 8px;border-style:none;padding:0px;" src="http://2.bp.blogspot.com/_QWaXq7W8dVI/R7wyAIlrv4I/AAAAAAAAAHg/0LeVcGwaY6Y/s320/lambda.jpg" border="0" alt="" /&gt;Eso es jiu-jitsu y lo demás, tonterías. Como advierte el propio autor, no es una técnica "práctica", pero es un logro impresionante por su complejidad conceptual... y por la elegancia, no del código en sí quizás, pero sí de las ideas teóricas que lo soportan.&lt;/div&gt;&lt;div class="p"&gt;El algoritmo de &lt;i&gt;raytracing&lt;/i&gt; tiene una característica importante: es recursivo. ¿Podemos, entonces, definir consultas recursivas en LINQ? Como las consultas LINQ están basadas en expresiones lambda, podemos ser más precisos: ¿se pueden definir expresiones lambdas recursivas en C&lt;sup&gt;#&lt;/sup&gt;?&lt;/div&gt;&lt;div class="p"&gt;La respuesta es afirmativa, pero la técnica necesaria es complicada... y resulta difícil de leer y mantener. Mads Torgersen la explica, desde una perspectiva teórica, aquí:&lt;/div&gt;&lt;ul type="square"&gt;&lt;li&gt;&lt;a href="http://blogs.msdn.com/madst/archive/2007/05/11/recursive-lambda-expressions.aspx" target="_blank"&gt;Recursive lambda expressions&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="p"&gt;Existe, no obstante, una técnica alternativa y algo más sencilla para resolver el problema. Octavio Hernández la explica en la página 85 de su libro &lt;a href="http://www.marteens.com/pdfs/linqbk.pdf" target="_blank"&gt;"C# 3.0 y LINQ"&lt;/a&gt; (que por cierto, puede &lt;a href="http://www.marteens.com/forms/linqform.htm" target="_blank"&gt;adquirir&lt;/a&gt; a través de nosotros). Esto que sigue es una explicación ampliada de la técnica.&lt;/div&gt;&lt;div class="p"&gt;¿Cuál es la dificultad para definir una función lambda recursiva? De entrada, que no podemos llamar directamente a la función por tratarse de una función &lt;i&gt;anónima&lt;/i&gt;. Lo que sí podríamos hacer es pasar un puntero a la función como parámetro de la misma, y ejecutar la función a la que hace referencia dicho puntero... o &lt;i&gt;delegado&lt;/i&gt;, en la jerga de .NET. El primer paso, por lo tanto, es definir un tipo delegado para funciones que se ajusten a este prototipo. Para simplificar, nos limitaremos a funciones que calculan un valor entero a partir de otro entero:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;delegate int&lt;/b&gt; &lt;font color="teal"&gt;Self&lt;/font&gt;(&lt;font color="teal"&gt;Self&lt;/font&gt; f, &lt;b&gt;int&lt;/b&gt; n);&lt;/pre&gt;&lt;div class="p"&gt;Construyamos ahora una función lambda que corresponda a este prototipo, y que simule el funcionamiento del factorial:&lt;/div&gt;&lt;pre class="pre"&gt;&lt;font color="teal"&gt;Self&lt;/font&gt; F = (f, n) =&amp;gt; n == 0 ? 1 : n * f(f, n - 1);&lt;/pre&gt;&lt;div class="p"&gt;Esta función &lt;i&gt;F&lt;/i&gt; (en mayúsculas) se parece extraordinariamente al factorial. ¿Qué hace falta para que sea "realmente" el factorial? Simplemente, que al llamarla pasemos, en el primero de sus parámetros, la función factorial... es decir, ella misma. Por lo tanto, la función que necesitamos es:&lt;/div&gt;&lt;pre class="p"&gt;&lt;font color="teal"&gt;Func&lt;/font&gt;&amp;lt;&lt;b&gt;int&lt;/b&gt;, &lt;b&gt;int&lt;/b&gt;&amp;gt; factorial = n =&amp;gt; F(F, n);&lt;/pre&gt;&lt;div class="p"&gt;Y ya tenemos función anónima recursiva. ¿Le cuesta todavía verlo claro? Bien, ahí va una pista:&lt;/div&gt;&lt;ul type="disc"&gt;&lt;li&gt;Observe que &lt;i&gt;F&lt;/i&gt; es realmente una variable local, no una "constante de función".&lt;/li&gt;&lt;li&gt;Cuando usamos &lt;i&gt;F&lt;/i&gt; para definir &lt;i&gt;factorial&lt;/i&gt;, en realidad estamos "capturando" la variable local &lt;i&gt;F&lt;/i&gt; dentro del cuerpo de la función anónima.&lt;/li&gt;&lt;li&gt;Es esta indirección la que permite, en definitiva, que el truco funcione.&lt;/li&gt;&lt;li&gt;Dicho sea de paso, observe que el identificador &lt;i&gt;f&lt;/i&gt;, usado al "inicializar" &lt;i&gt;F&lt;/i&gt;, es en realidad un parámetro de tipo delegado.&lt;/li&gt;&lt;li&gt;¿Se ha dado cuenta de que he dicho "inicializar &lt;i&gt;F&lt;/i&gt;" en vez de "definir &lt;i&gt;F&lt;/i&gt;"?&lt;/li&gt;&lt;/ul&gt;&lt;div class="p"&gt;Octavio termina su truco en este punto, y aunque se ha resuelto el problema, nos queda cierta insatisfacción, por haber utilizado el paso intermedio de la inicialización de &lt;i&gt;F&lt;/i&gt;. Sin embargo, con muy poco esfuerzo más, se pueden mezclar las dos funciones anónimas y definir el factorial en un único paso. Esta es la expresión lambda que buscábamos:&lt;/div&gt;&lt;pre class="p"&gt;&lt;font color="teal"&gt;Func&lt;/font&gt;&amp;lt;&lt;b&gt;int&lt;/b&gt;, &lt;b&gt;int&lt;/b&gt;&amp;gt; factorial = i =&amp;gt;&lt;br /&gt;    &lt;b&gt;new&lt;/b&gt; &lt;font color="teal"&gt;Self&lt;/font&gt;((f, j) =&amp;gt; j == 0 ? 1 : j * f(f, j - 1))(&lt;br /&gt;        (f, j) =&amp;gt; j == 0 ? 1 : j * f(f, j - 1), i);&lt;/pre&gt;&lt;div class="p"&gt;Es necesario utilizar explícitamente el constructor de &lt;i&gt;Self&lt;/i&gt;, el tipo delegado, para que el compilador reconozca la expresión y pueda realizar la inferencia del resto de los tipos de parámetros. Para entender este monstruo, es mejor dividirlo en zonas:&lt;/div&gt;&lt;pre class="p"&gt;&lt;font color="teal"&gt;Func&lt;/font&gt;&amp;lt;&lt;b&gt;int&lt;/b&gt;, &lt;b&gt;int&lt;/b&gt;&amp;gt; factorial = i =&amp;gt;&lt;br /&gt;    &lt;span style="background-color: #ffffC0;"&gt;&lt;b&gt;new&lt;/b&gt; &lt;font color="teal"&gt;Self&lt;/font&gt;((f, j) =&amp;gt; j == 0 ? 1 : j * f(f, j - 1))&lt;/span&gt;&lt;br /&gt;    (&lt;br /&gt;        &lt;span style="background-color: #C0ffC0;"&gt;(f, j) =&amp;gt; j == 0 ? 1 : j * f(f, j - 1)&lt;/span&gt;,&lt;br /&gt;        &lt;span style="background-color: #C0C0ff;"&gt;i&lt;/span&gt;&lt;br /&gt;    );&lt;/pre&gt;&lt;ul type="disc"&gt;&lt;li&gt;La expresión amarilla se evalúa y produce un delegado. Observe que la usamos sintácticamente del mismo modo en que usaríamos &lt;i&gt;Math.Sqrt&lt;/i&gt; o &lt;i&gt;Console.WriteLine&lt;/i&gt;. En cierto sentido perverso y retorcido, &lt;i&gt;Sqrt&lt;/i&gt; es una "constante de función", mientras que nuestro monstruo es una expresión que se evalúa y produce una función.&lt;/li&gt;&lt;li&gt;¿Se ha dado cuenta de que la expresión verde es estructuralmente idéntica a la amarilla? No obstante, la expresión verde no se evalúa directamente, sino que la pasamos como parámetro para que se ejecute más adelante.&lt;/li&gt;&lt;li&gt;Finalmente, tenemos la simple y vulgar expresión azul. No hay misterio aquí, ¿verdad?&lt;/li&gt;&lt;/ul&gt;&lt;div class="p"&gt;¿Complicado? Es cierto, pero la gracia de todo esto es que existe un truco alternativo, mucho más simple. Observe:&lt;/div&gt;&lt;pre class="p"&gt;&lt;font color="teal"&gt;Func&lt;/font&gt;&amp;lt;&lt;b&gt;int&lt;/b&gt;, &lt;b&gt;int&lt;/b&gt;&amp;gt; factorial = &lt;b&gt;null&lt;/b&gt;;&lt;br /&gt;factorial = i =&amp;gt; i == 0 ? 1 : i * factorial(i - 1);&lt;/pre&gt;&lt;div class="p"&gt;Primero se declara una variable que apuntará a la función y se inicializa con un nulo. Luego se asigna el delegado definitivo... que hace referencia en su cuerpo a la variable local. Se trata de una &lt;i&gt;captura de variable local&lt;/i&gt;, una técnica no sólo permitida por el lenguaje: es, en realidad, lo que hace que todo este rollo de las funciones anónimas tenga sentido. Lo que ahora importa es que, cuando ejecutemos el método asociado a la variable &lt;i&gt;factorial&lt;/i&gt;, ésta ya estará debidamente inicializada.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-889828936085444606?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/889828936085444606/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=889828936085444606&amp;isPopup=true' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/889828936085444606'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/889828936085444606'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/02/recursividad-annima.html' title='Recursividad anónima'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_QWaXq7W8dVI/R7wyAIlrv4I/AAAAAAAAAHg/0LeVcGwaY6Y/s72-c/lambda.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-6541394478476726210</id><published>2008-02-09T17:46:00.000+01:00</published><updated>2008-12-11T09:01:31.955+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='XSight'/><title type='text'>XSight RT v1.1, para .NET v3.5</title><content type='html'>&lt;div class="p"&gt;&lt;img style="float:right; margin:1px 0 1px 8px; border-style:none;padding:0px;" src="http://4.bp.blogspot.com/_QWaXq7W8dVI/R63wxYlrv3I/AAAAAAAAAHY/8_LA7rSwtvs/s320/csg.jpg" border="0" alt="" /&gt;&lt;span class="first"&gt;Si se aburre, puede&lt;/span&gt; entretenerse un poco experimentando con &lt;a href="http://www.marteens.com/zips/XSightRT11.zip"&gt;XSight RT v1.1&lt;/a&gt;, para .NET Framework 3.5. La descarga contiene el instalador del ejecutable, la ayuda y un puñado de escenas para pruebas. No he incluido el código fuente.&lt;/div&gt;&lt;div class="p"&gt;La aplicación permite editar escenas con un lenguaje sencillo y bien documentado, y generar imágenes a partir de estas descripciones. De momento, funciona como una aplicación SDI, permitiendo trabajar con un único documento por instancia de la misma. No está conectado todavía el soporte de refracción y transparencias, ni la perturbación de normales (es una técnica con un nombre perturbador).&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-6541394478476726210?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/6541394478476726210/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=6541394478476726210&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/6541394478476726210'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/6541394478476726210'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/02/xsight-rt-v11-para-net-v35.html' title='XSight RT v1.1, para .NET v3.5'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_QWaXq7W8dVI/R63wxYlrv3I/AAAAAAAAAHY/8_LA7rSwtvs/s72-c/csg.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-7085299971898581168</id><published>2008-01-17T15:23:00.000+01:00</published><updated>2008-12-11T09:01:32.111+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ideas'/><category scheme='http://www.blogger.com/atom/ns#' term='programación funcional'/><category scheme='http://www.blogger.com/atom/ns#' term='XSight'/><title type='text'>SILLY</title><content type='html'>&lt;div&gt;&lt;img style="float:right; margin:1px 0 1px 8px;border-style:none;padding:0px;" src="http://1.bp.blogspot.com/_QWaXq7W8dVI/R49x2frSXVI/AAAAAAAAAHQ/18kRr_vcjKg/s320/gear.jpg" border="0" alt="" /&gt;&lt;span class="first"&gt;No, no estoy llamando&lt;/span&gt; "tonto" a nadie: es el nombre que se me ocurrió para el lenguaje de descripción de escenas de &lt;a href="http://www.marteens.com/xsight" target="_blank"&gt;XSight RT&lt;/a&gt;, y significa, simplemente, &lt;i&gt;Small Instantiation Language&lt;/i&gt;... claro, añadiéndole el sufijo de los adverbios ingleses.&lt;/div&gt;&lt;div&gt;El caso es que se trata de un lenguaje orientado a la creación de objetos; de ahí lo de &lt;i&gt;Instantiation&lt;/i&gt;. Resulta también que hay un gran números de circunstancias en los que esa "categoría" de minilenguajes resulta útil. ¿Quiere otro ejemplo? Ahí tiene la generación de compiladores. Freya utiliza &lt;a href="http://www.devincook.com" target="_blank"&gt;GOLD&lt;/a&gt;: un sistema que recibe una gramática y produce una tabla de análisis sintáctico. Pero es más común el uso de sistemas como Yacc y Bison, que permiten asociar instrucciones en C/C++/C&lt;sup&gt;#&lt;/sup&gt; a la gramática. Hace poco encontré &lt;a href="http://plas.fit.qut.edu.au/gppg/" target="_blank"&gt;este otro generador&lt;/a&gt;, de Wayne Kelly, de la Queensland University of Technology. Incluye el código fuente completo del generador, en C&lt;sup&gt;#&lt;/sup&gt;, y es un código limpio y legible.&lt;/div&gt;&lt;div&gt;Tengo, desde hace un tiempo, la idea de ensayar el uso de un lenguaje tipo SILLY con un generador de compiladores para .NET. Como el análisis sintáctico suele utilizarse para crear, en paralelo, un &lt;i&gt;Arbol de Sintaxis Abstracta&lt;/i&gt; (AST), el lenguaje se especializaría en la creación de objetos. Algunas ideas sencillas:&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Nada de operador &lt;b&gt;new&lt;/b&gt;. Cuando un nombre de tipo se usa como función, significa la construcción de una instancia.&lt;/li&gt;&lt;li&gt;El lenguaje soportaría &lt;i&gt;inicializadores de objetos&lt;/i&gt;... al estilo Freya, claro. Es decir, se podrían inicializar campos y propiedades del objeto creado usando una sintaxis similar a la de los parámetros con nombre.&lt;/li&gt;&lt;li&gt;Cada "no terminal" de la gramática tendría un tipo de datos asociado.&lt;/li&gt;&lt;li&gt;Cada "regla", o "producción", tendría una expresión asociada, de un tipo derivado del tipo asociado al no terminal.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Veamos un ejemplo sencillo:&lt;/div&gt;&lt;pre class="p"&gt;&amp;lt;Exp&amp;gt; ::=          : AstExp&lt;br /&gt;  &amp;lt;Exp&amp;gt; '+' &amp;lt;Term&amp;gt; : AstBinary($Exp, '+', $Term)&lt;br /&gt;  &amp;lt;Term&amp;gt;           : $Term&lt;/pre&gt;&lt;div&gt;La primera línea advierte que las expresiones van asociadas a nodos de la clase &lt;i&gt;AstExp&lt;/i&gt;. En la segunda, cada vez que se detecta una suma, se crea un nodo &lt;i&gt;AstBinary&lt;/i&gt; a partir de los nodos de las partes constituyentes. La tercera línea indica que se copie, simplemente, el nodo asociado al término. Este es, naturalmente, el caso más sencillo y frecuente. También es frecuente el uso de listas, por lo que esta variante de SILLY debería soportarlas:&lt;/div&gt;&lt;pre class="p"&gt;&amp;lt;VarGroup&amp;gt; ::=         : List[AstVar]&lt;br /&gt;  &amp;lt;VarGroup&amp;gt; ',' &amp;lt;Var&amp;gt; : $VarGroup + { $Var }&lt;br /&gt;  &amp;lt;Var&amp;gt;                : { $Var }&lt;/pre&gt;&lt;div&gt;Es decir, las llaves se utilizarían para delimitar &lt;i&gt;literales de listas&lt;/i&gt;, y el signo + significaría "unión", o concatenación de listas.&lt;/div&gt;&lt;div&gt;Ahora mire un "invento" curioso, asociado a la regla sintáctica correspondiente al &lt;a href="http://freyalang.blogspot.com/2007/11/ranges.html" target="_blank"&gt;operador existencial de Freya&lt;/a&gt;:&lt;/div&gt;&lt;pre class="p"&gt;&lt;br /&gt;&amp;lt;Exp&amp;gt; ::=      : AstExp&lt;br /&gt;  '*' IN &amp;lt;Exp&amp;gt; : &lt;b&gt;if&lt;/b&gt; $Exp &lt;b&gt;is&lt;/b&gt; AstRange&lt;br /&gt;                   &lt;b&gt;then&lt;/b&gt; AstBin($Exp.Lo, "&amp;lt;=", $Exp.Hi)&lt;br /&gt;                   &lt;b&gt;else&lt;/b&gt; AstExists($Exp)&lt;/pre&gt;&lt;div&gt;Para empezar, observe que he mostrado una &lt;i&gt;expresión condicional&lt;/i&gt;, no una &lt;i&gt;instrucción condicional&lt;/i&gt;. Lo interesante es lo que ocurre en la rama &lt;b&gt;then&lt;/b&gt; de la expresión: como esa rama se evalúa cuando &lt;i&gt;$Exp&lt;/i&gt; es un &lt;i&gt;AstRange&lt;/i&gt;, cambiamos el tipo declarado para &lt;i&gt;$Exp&lt;/i&gt; de esa rama para abajo (en el árbol de expresiones); por eso permitimos las referencias a las propiedades &lt;i&gt;Lo&lt;/i&gt; y &lt;i&gt;Hi&lt;/i&gt; (&lt;i&gt;low&lt;/i&gt; y &lt;i&gt;high&lt;/i&gt;), definidas para &lt;i&gt;AstRange&lt;/i&gt;. Creo que un convenio de este tipo ahorraría mucho trabajo y sería muy útil en lenguajes de propósito general... aunque tengo que pensarlo un poco más, antes de dar el recurso por bueno.&lt;/div&gt;&lt;div&gt;Naturalmente, se permitiría expresiones &lt;b&gt;let&lt;/b&gt;/&lt;b&gt;where&lt;/b&gt;, y quizás sería necesario algún "aplicador" para actuar sobre elementos de una lista. El "compilador" tendría que encargarse también de algo que podemos clasificar como &lt;i&gt;inyección de código&lt;/i&gt;: se supone que, a la vez que se construye el árbol sintáctico, los nodos de éste deben irse asociando a intervalos o rangos de texto dentro del código fuente. A los nodos devueltos en cada reducción, por ejemplo, se les podría asociar automáticamente al rango determinado por el texto reducido. Pero habría casos más complicados:&lt;/div&gt;&lt;pre class="p"&gt;&amp;lt;Exp&amp;gt; ::=            : AstExp&lt;br /&gt;  &amp;lt;Exp&amp;gt; IS NOT &amp;lt;Ref&amp;gt; : AstNeg(AstCast($1, $3))&lt;/pre&gt;&lt;div&gt;El nodo &lt;i&gt;AstNeg&lt;/i&gt; es el inmediatamente devuelto por la reducción, por lo que es fácil asignarle un rango. En cambio, el nodo &lt;i&gt;AstCast&lt;/i&gt; se esconde dentro del nodo principal. Una solución laboriosa sería indicar explícitamente la asignación del rango:&lt;/div&gt;&lt;pre class="p"&gt;AstNeg(AstCast($1, $3, Range := @1 + @3))&lt;/pre&gt;&lt;div&gt;Este es un ejemplo de los inicializadores de objetos ya mencionados. Observe que &lt;i&gt;@1&lt;/i&gt; se refiere al rango asociado al primer nodo de la regla. Otra solución más elegante sería permitir que el compilador dedujese dicha asignación, a partir de los parámetros detectados en la llamada al constructor &lt;i&gt;AstCast&lt;/i&gt;.&lt;/div&gt;&lt;div&gt;¿Qué le parece?&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-7085299971898581168?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/7085299971898581168/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=7085299971898581168&amp;isPopup=true' title='6 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7085299971898581168'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7085299971898581168'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/01/silly.html' title='SILLY'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_QWaXq7W8dVI/R49x2frSXVI/AAAAAAAAAHQ/18kRr_vcjKg/s72-c/gear.jpg' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-4016830356837703694</id><published>2008-01-11T12:28:00.000+01:00</published><updated>2008-01-11T13:27:16.055+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Marteens'/><title type='text'>Estadísticas y curiosidades</title><content type='html'>&lt;div&gt;&lt;span class="first"&gt;Me ha sorprendido que&lt;/span&gt; cierto artículo sobre ADO.NET 2.0, escrito casi al principio del ciclo de vida del producto, cuando aún se llamaba Whidbey, se sigue descargando de mi página el doble de las veces que Intuitive C#, el libro gratuito sobre el lenguaje. No hay nada de malo en ello, excepto que no tenía consciencia del hecho... y que me preocupa la actualidad del contenido del famoso artículo, como podrá imaginar (no he incluido el enlace para no "agravar" el fenómeno). Supongo que tendré que retocar un poco el contenido, para evitar confusiones. También empezaré a fechar los artículos: tengo algunas malas experiencias con citas, por parte de terceros, de artículos del año cataplum, con referencia a tecnología de aquellas fechas.&lt;/div&gt;&lt;div&gt;Por cierto, no se hemos pasado todavía la primera quincena del año, ¡y ya aparecen en mis estadísticas varias consultas sobre el &lt;a href="http://www.marteens.com/trick2f.htm" target="_blank"&gt;principio de indeterminación de Heisenberg&lt;/a&gt;!&lt;/div&gt;&lt;hr class="p"&gt;&lt;div&gt;Por cierto, si aún sigue usando la versión 2005 de Visual Studio... ¡pásese ya a la 2008! Visual Studio 2008 permite configurar la versión de .NET Framework para la que compila los proyectos. De manera que, si no quiere migrar sus aplicaciones a .NET 3.5 por el motivo que sea, no está obligado a hacerlo: puede seguir usando .NET 2.0, pero con Visual Studio 2008, y postergar el cambio de versión de su aplicación &lt;i&gt;per secula seculorum&lt;/i&gt;. ¿La ventaja?, pues que, a pesar de seguir usando esa versión de la plataforma, Visual Studio 2008 le permitirá usar buena parte de las extensiones de C&lt;sup&gt;#&lt;/sup&gt; 3.0.&lt;/div&gt;&lt;div&gt;Desventajas: VS2008 está todavía en inglés. Hay también un punto negro: las operaciones "Buscar todas las referencias" y el cambio de nombre de un identificador tardan más que en VS2005, o esa es la impresión que me he llevado. He leído en algún lugar que, en esta versión, el equipo de VS2008 unificó los &lt;i&gt;bindings&lt;/i&gt;: en la jerigonza del entorno de desarrollo, eso de los "bindings" se refiere al uso de partes del compilador y del analizador lexical para asuntos como IntelliSense, la navegación por clases y miembros, etc. Es algo muy normal que, en un entorno de desarrollo como VS2008, se utilicen distintos compiladores y analizadores especializados para estas tareas, con el imaginable coste adicional del mantenimiento de los mismos. Al parecer, han hecho cambios para unificar la base de código... y mi impresión es que algunas operaciones son ahora más lentas. Pero, en general, creo que merece la pena el cambio.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-4016830356837703694?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/4016830356837703694/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=4016830356837703694&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/4016830356837703694'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/4016830356837703694'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/01/estadsticas-y-curiosidades.html' title='Estadísticas y curiosidades'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-1080822582434001179</id><published>2008-01-09T15:19:00.000+01:00</published><updated>2008-01-09T20:07:57.644+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Freya'/><category scheme='http://www.blogger.com/atom/ns#' term='interface'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='CLR'/><title type='text'>Clases anidadas dentro de interfaces</title><content type='html'>&lt;div&gt;&lt;span class="first"&gt;C&lt;sup&gt;#&lt;/sup&gt; no lo permite&lt;/sup&gt;&lt;/span&gt;, pero el CLR no pone objeciones:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;.class public interface abstract auto ansi&lt;/b&gt; MyInt&lt;br /&gt;{&lt;br /&gt;    &lt;b&gt;.class abstract auto ansi sealed nested public&lt;/b&gt; MyExt&lt;br /&gt;        &lt;b&gt;extends&lt;/b&gt; [mscorlib]System.Object&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;div&gt;El listado anterior muestra una clase estática anidada dentro de un tipo de interfaz. Naturalmente, para poder crear este "engendro" he tenido que usar el API de reflexión, porque ninguno de los lenguajes actuales acepta un tipo anidado dentro de una interfaz.&lt;/div&gt;&lt;div&gt;¿Para qué necesito esto? Resulta que es la forma más elegante de definir métodos de extensión para un tipo de interfaz:&lt;/div&gt;&lt;pre class="p"&gt;&lt;font color="teal"&gt;IStack&lt;/font&gt; = &lt;b&gt;interface&lt;/b&gt;[X]&lt;br /&gt;    IsEmpty: &lt;font color="teal"&gt;Boolean&lt;/font&gt;;&lt;br /&gt;    Top: X;&lt;br /&gt;    &lt;b&gt;method&lt;/b&gt; Push(Value: X);&lt;br /&gt;    &lt;b&gt;method&lt;/b&gt; Pop;&lt;/pre&gt;&lt;pre class="p" style="MARGIN-TOP: 4px"&gt;&lt;div style="MARGIN: 0px; BACKGROUND-COLOR: #d0d0d0; line-height:normal;"&gt;    &lt;b&gt;method&lt;/b&gt; Clear;&lt;br /&gt;    &lt;b&gt;begin&lt;br /&gt;        while not&lt;/b&gt; IsEmpty &lt;b&gt;do&lt;/b&gt; Pop;&lt;br /&gt;    &lt;b&gt;end&lt;/b&gt;;&lt;/div&gt;&lt;b&gt;end&lt;/b&gt;;&lt;/pre&gt;&lt;div&gt;El truco, por supuesto, consistiría en generar una clase estática adicional, con métodos de extensión. El problema es más bien estético: la proliferación de clases con nombres extraños en el espacio de nombres del programador (el mecanismo usado por C&lt;sup&gt;#&lt;/sup&gt; y compañía para "activar" las extensiones es un desastre).&lt;/div&gt;&lt;div&gt;La solución puede ser anidar la clase con las extensiones en el tipo de interfaz. Primera dificultad: ya hemos visto que está prohibido en los compiladores, pero no en el &lt;i&gt;runtime&lt;/i&gt;, de Microsoft. Segunda dificultad: resulta que C&lt;sup&gt;#&lt;/sup&gt; no permite tampoco métodos de extensión dentro de una clase anidada. Esto va a complicar la compatibilidad de los métodos generados en Freya con este mecanismo: lo más que se puede hacer es ofrecer un &lt;i&gt;switch&lt;/i&gt; de compatibilidad. Si está inactivo, porque la aplicación o el ensamblado van a ser consumidos desde Freya, los métodos de extensión asociados directamente a interfaces se generarán en una clase anidada. En caso contrario, se utilizará el horroroso sistema actualmente empleado por Microsoft.&lt;/div&gt;&lt;div&gt;Ocurre que existen motivos adicionales para investigar en esta dirección: Freya permite definir aserciones en un tipo de interfaz (la última vez que eché un vistazo a Chrome, éste no lo permitía). Si un tipo de interfaz representa la definición de un "contrato", ¿qué hay más natural que permitir reglas que precisen los términos de dicho contrato? Por desgracia, precondiciones y postcondiciones generan código, y de momento, Freya estaba generando ese código en clases auxiliares. Con el nuevo mecanismo, podremos encapsular este código en clases anidadas, y despejar un poco el espacio de diseño.&lt;/div&gt;&lt;hr class="p"&gt;&lt;div&gt;... y aprovecho para aclarar un poco la relación entre aserciones, interfaces y métodos de extensión. Supongamos un caso muy sencillo de interfaz con una precondición:&lt;/div&gt;&lt;pre class="p"&gt;&lt;font color="teal"&gt;IStack&lt;/font&gt; = &lt;b&gt;interface&lt;/b&gt;[X]&lt;br /&gt;    &lt;b&gt;property&lt;/b&gt; IsEmpty: &lt;font color="teal"&gt;Boolean&lt;/font&gt;;&lt;br /&gt;    &lt;b&gt;method&lt;/b&gt; Pop;&lt;br /&gt;        &lt;b&gt;requires not&lt;/b&gt; IsEmpty;&lt;br /&gt;    // ...&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;;&lt;/pre&gt;&lt;div&gt;Ahora mismo, Freya genera una clase estática con métodos para cada aserción de la interfaz. Como se trata de miembros de una interfaz, necesariamente públicos, no hay problema con los niveles de acceso. Con la nueva idea de implementaciones en interfaces (formalmente, se puede hablar de &lt;i&gt;traits&lt;/i&gt; o &lt;i&gt;mixins&lt;/i&gt;, aunque no es exactamente lo mismo), lo que haríamos ahora sería equivalente a generar un método "de extensión" en la interfaz:&lt;/div&gt;&lt;pre class="p"&gt;&lt;font color="teal"&gt;IStack&lt;/font&gt; = &lt;b&gt;interface&lt;/b&gt;[X]&lt;br /&gt;    &lt;b&gt;property&lt;/b&gt; IsEmpty: &lt;font color="teal"&gt;Boolean&lt;/font&gt;;&lt;br /&gt;    &lt;b&gt;method&lt;/b&gt; Pop;&lt;br /&gt;    // ...&lt;br /&gt;    &lt;b&gt;method&lt;/b&gt; Pop$Pre;&lt;br /&gt;    &lt;b&gt;begin&lt;br /&gt;        if&lt;/b&gt; Self.IsEmpty &lt;b&gt;then&lt;/b&gt;&lt;br /&gt;            &lt;b&gt;raise new&lt;/b&gt; &lt;font color="teal"&gt;Exception&lt;/font&gt;;&lt;br /&gt;    &lt;b&gt;end&lt;/b&gt;;&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;;&lt;/pre&gt;&lt;ol&gt;&lt;li&gt;En realidad, &lt;i&gt;Pop$Pre&lt;/i&gt; sería un método estático dentro de una clase estática anidada, que recibiría un puntero de tipo &lt;i&gt;IStack[X]&lt;/i&gt;.&lt;/li&gt;&lt;li&gt;Observe el truco del nombre: como el dólar no es aceptado dentro de un identificador, el programador no tendría acceso directo al método. Es un truco bastante usado, incluso por el compilador de C&lt;sup&gt;#&lt;/sup&gt;.&lt;/li&gt;&lt;li&gt;Toda clase que implementase &lt;i&gt;IStack[X]&lt;/i&gt;, siempre que se programase en Freya, añadiría automáticamente una precondición a su implementación de &lt;i&gt;Pop&lt;/i&gt;, que ejecutaría el método &lt;i&gt;Pop$Pre&lt;/i&gt; sobre el objeto activo convertido en el tipo de interfaz.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;¿La ventaja de anidar la clase auxiliar dentro de la interfaz? Hasta ahora, Freya generaba una clase interna independiente... y tenía que cumplir con un estricto protocolo de asignaciones de nombres para detectar estas clases al leer un ensamblado generado en otro proyecto Freya. Con esta idea, por el contrario, la asociación entre la interfaz y la clase auxiliar es inmediata.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-1080822582434001179?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/1080822582434001179/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=1080822582434001179&amp;isPopup=true' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/1080822582434001179'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/1080822582434001179'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/01/clases-anidadas-dentro-de-interfaces.html' title='Clases anidadas dentro de interfaces'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-4554753523423250998</id><published>2008-01-07T21:20:00.000+01:00</published><updated>2008-12-11T09:01:32.166+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='atributos'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>DebuggerDisplayAttribute</title><content type='html'>&lt;div&gt;&lt;span class="first"&gt;Un truco sencillo que acabo&lt;/span&gt; de descubrir. Observe la imagen:&lt;/div&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;" src="http://4.bp.blogspot.com/_QWaXq7W8dVI/R4KJifrSXUI/AAAAAAAAAHI/6qLmZV_On-8/s1600/debdisp.jpg" border="0" alt="" /&gt;&lt;div&gt;Depurando, si paso el ratón sobre el parámetro &lt;i&gt;map&lt;/i&gt;, que pertenece a un tipo &lt;i&gt;TypeMap&lt;/i&gt; que he definido, se muestra el número de elementos almacenados por este contenedor. ¿Cómo se logra? Parece sencillo: basta con redefinir el método &lt;i&gt;ToString&lt;/i&gt; en la clase &lt;i&gt;TypeMap&lt;/i&gt;. Y es verdad que &lt;i&gt;eso&lt;/i&gt; funciona... pero hay una alternativa que muchas veces es mejor. Se trata de decorar la clase con el atributo &lt;i&gt;DebuggerDisplay&lt;/i&gt;:&lt;/div&gt;&lt;pre class="p"&gt;[&lt;font color="teal"&gt;DebuggerDisplay&lt;/font&gt;("Items = {items.Count}")]&lt;br /&gt;&lt;b&gt;internal sealed class&lt;/b&gt; &lt;font color="teal"&gt;TypeMap&lt;/font&gt;&lt;/pre&gt;&lt;div&gt;Observe que el parámetro pasado al atributo es una especie de cadena de formato que permite incluir expresiones entre llaves. En este caso, mostramos el valor de la propiedad &lt;i&gt;Count&lt;/i&gt; de un campo de &lt;i&gt;TypeMap&lt;/i&gt; llamado &lt;i&gt;items&lt;/i&gt;.&lt;/div&gt;&lt;div&gt;¿Porque me alegra tanto tener una alternativa a la redefinición de &lt;i&gt;ToString&lt;/i&gt;? Porque así puedo separar con más claridad la lógica de la aplicación del código auxiliar que sólo necesito durante la depuración del proyecto. En el compilador de Freya, por ejemplo, los símbolos de métodos redefinen &lt;i&gt;ToString&lt;/i&gt; para facilitar la búsqueda en la tabla de símbolos, pero otras clases lo hacían sólo por conveniencia, para mostrar información durante la depuración. Con el listado delante, me costaba normalmente decidir si determinada reescritura de &lt;i&gt;ToString&lt;/i&gt; era necesaria o prescindible.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-4554753523423250998?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/4554753523423250998/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=4554753523423250998&amp;isPopup=true' title='11 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/4554753523423250998'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/4554753523423250998'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/01/debuggerdisplayattribute.html' title='DebuggerDisplayAttribute'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_QWaXq7W8dVI/R4KJifrSXUI/AAAAAAAAAHI/6qLmZV_On-8/s72-c/debdisp.jpg' height='72' width='72'/><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-4757611766489710574</id><published>2008-01-05T18:34:00.000+01:00</published><updated>2008-12-11T09:01:32.389+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='RPC'/><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><title type='text'>UpdateBatchSize</title><content type='html'>&lt;div&gt;&lt;img style="float:right; margin:0px 0 0px 7px;border-style:none;padding:0px;" src="http://3.bp.blogspot.com/_QWaXq7W8dVI/R3_c4_rSXTI/AAAAAAAAAHA/9saMmk4K8Kk/s320/parade.jpg" border="0" alt="Marshaling" /&gt;&lt;span class="first"&gt;Todo programador que haya&lt;/span&gt; trabajado con SQL Server sabe lo importante que es empaquetar cuantas instrucciones sea posible dentro de una misma petición al servidor. El mismo programador, cuando comienza a trabajar con ADO.NET tropieza con la paradoja de que cada actualización de registros modificados en un &lt;i&gt;dataset&lt;/i&gt;, debe viajar al servidor SQL completamente sola. Al menos, en la versión 1.1 era esto lo que ocurría...&lt;/div&gt;&lt;h3&gt;Tinieblas&lt;/h3&gt;&lt;div&gt;El problema, aclaro, no es grave. Típicamente, cuando se producen actualizaciones a través de modificaciones en un &lt;i&gt;DataSet&lt;/i&gt;, estas modificaciones afectan a muy pocos registros, y el peaje a pagar es poco. Por el contrario, si usted se despierta un día actualizando centenares de registros a través de un &lt;i&gt;data adapter&lt;/i&gt;, corra a visitar a su psicólogo de cabecera. Para actualizaciones masivas, es mejor usar directamente SQL, y si es posible, mediante procedimientos almacenados. Ese mítico escenario del feliz programador OOP que transparentemente modifica instancias de clases generadas por un ORM es una gran mentira: en una aplicación real, la mayoría de las modificaciones que no se realizan en el servidor mediante procedimientos almacenados, se generan a petición de controles enlazados a datos... a no ser que usted sienta fobia hacia el enlace de datos y los procedimientos almacenados.&lt;/div&gt;&lt;div&gt;De todos modos, las clases &lt;i&gt;SqlDataAdapter&lt;/i&gt; y &lt;i&gt;OracleDataAdapter&lt;/i&gt; de .NET 2.0 introdujeron una propiedad &lt;i&gt;UpdateBatchSize&lt;/i&gt;, que permite agrupar varias actualizaciones en una misma petición. Si la propiedad vale &lt;i&gt;1&lt;/i&gt;, que es su valor por omisión, el comportamiento de los adaptadores es el de la versión anterior: una petición separada para cada registro actualizado. Un &lt;i&gt;0&lt;/i&gt; en la propiedad provoca que todas las actualizaciones se sumen y se envíen en un único viaje de ida y vuelta. Y, finalmente, cualquier valor mayor que &lt;i&gt;1&lt;/i&gt; sirve para crear grupos de peticiones del tamaño indicado.&lt;/div&gt;&lt;div&gt;Confieso, sin embargo, que hasta hace muy poco, nunca había usado esta propiedad. El motivo tiene que ver con la mecánica de las actualizaciones en ADO.NET. Suponga que tratamos con un una tabla cuya clave primaria es una columna autoincremental, y que tiene un campo de tipo &lt;b&gt;rowversion&lt;/b&gt;/&lt;b&gt;timestamp&lt;/b&gt; para el control optimista de concurrencia. Las inserciones en esta tabla se ejecutan mediante el siguiente grupo de instrucciones SQL:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;insert into&lt;/b&gt; Clientes(...) &lt;b&gt;values&lt;/b&gt; (...);&lt;br /&gt;&lt;b&gt;select&lt;/b&gt; IDCliente, TS &lt;b&gt;from&lt;/b&gt; Clientes&lt;br /&gt;&lt;b&gt;where&lt;/b&gt;  IDCliente = SCOPE_IDENTITY()&lt;/pre&gt;&lt;div&gt;En otras palabras: cuando se inserta un registro, inmediatamente después se pide la última identidad creada al servidor, y el valor de la versión de fila para la nueva fila. Estos dos valores se devuelven al adaptador como un &lt;i&gt;recordset&lt;/i&gt; de una fila, y el adaptador utiliza estos valores para poner al día las correspondientes columnas en el &lt;i&gt;dataset&lt;/i&gt;.&lt;/div&gt;&lt;div&gt;¿Qué ocurriría si agrupásemos varias de estas instrucciones en un mismo &lt;i&gt;batch&lt;/i&gt; o grupo de consultas? Evidentemente, el mecanismo saltaría por los aires. El servidor respondería enviando una colección de &lt;i&gt;recordsets&lt;/i&gt;, pero el adaptador sería incapaz de distinguir cuál correspondería a cada fila. Es natural que el programador se abstenga de usar &lt;i&gt;UpdateBatchSize&lt;/i&gt;, pues aparentemente obligaría a utilizar otro sistema para la puesta al día de la copia local de los datos tras una actualización.&lt;/div&gt;&lt;h3&gt;Fiat lux&lt;/h3&gt;&lt;div&gt;Pero, ¡pobre de mí!, no sospechaba cuán listos habían sido los que añadieron esta característica a los adaptadores. Hace poco, haciendo pruebas, me di cuenta de que un adaptador con &lt;i&gt;UpdateBatchSize&lt;/i&gt; parecía seguir enviando consultas individuales al servidor SQL. Al menos, en el SQL Profiler se mostraban las inserciones como instrucciones individuales. Intrigado, busqué más información en Internet, y así supe que la labor de &lt;i&gt;UpdateBatchSize&lt;/i&gt; no consiste en generar una única petición formada por una gigantesca instrucción. La técnica es más sofisticada, y según lo que sé, consiste en agrupar todas las peticiones en un único paquete RPC (&lt;i&gt;Remote Procedure Call&lt;/i&gt;). Esto ahorra un ancho de banda considerable, y lo que es más importante, disminuye los problemas de latencia provocados por la red. No se optimiza la operación, considerada por separado, al máximo, pero se logra un mejor resultado, de todos modos... y abre el camino a la esperanza.&lt;/div&gt;&lt;div&gt;Volví entonces a la documentación de &lt;i&gt;SqlDataAdapter&lt;/i&gt; y descubrí un pequeño detalle: cuando &lt;i&gt;BatchUpdateSize&lt;/i&gt; es distinto de &lt;i&gt;1&lt;/i&gt;, los comandos del adaptador no pueden tener los valores &lt;i&gt;Both&lt;/i&gt; o &lt;i&gt;FirstReturnedRecord&lt;/i&gt; en su propiedad &lt;i&gt;UpdateSource&lt;/i&gt;. Es decir: no se puede usar un &lt;i&gt;recordset&lt;/i&gt; para poner al día la copia local. Pero esto también significa que se admite la opción &lt;i&gt;OutputParameters&lt;/i&gt;. Si la actualización se realiza a través de procedimientos almacenados, ¡es posible usar &lt;i&gt;UpdateBatchSize&lt;/i&gt; y seguir actualizando la copia local en una misma operación!&lt;/div&gt;&lt;div&gt;En estos casos, hay que tener un procedimiento almacenado en el servidor parecido a éste:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;create procedure&lt;/b&gt; InsertCliente&lt;br /&gt;    @IdCliente &lt;b&gt;int output&lt;/b&gt;,&lt;br /&gt;    @TS &lt;b&gt;timestamp output&lt;/b&gt;,&lt;br /&gt;    @Nombre T_NOMBRE,&lt;br /&gt;    @Apellidos T_APELLIDOS &lt;b&gt;as&lt;/b&gt;&lt;br /&gt;    &lt;b&gt;insert into&lt;/b&gt; Clientes(Nombre, Apellidos)&lt;br /&gt;    &lt;b&gt;values&lt;/b&gt; (@Nombre, @Apellidos);&lt;br /&gt;    &lt;b&gt;select&lt;/b&gt; @IdCliente = IDCliente, @TS = TS&lt;br /&gt;    &lt;b&gt;from&lt;/b&gt;   Clientes&lt;br /&gt;    &lt;b&gt;where&lt;/b&gt;  IDCliente = SCOPE_IDENTITY()&lt;/pre&gt;&lt;div&gt;Observe que esta vez no se utiliza un &lt;i&gt;recordset&lt;/i&gt;, sino los parámetros de salida del procedimiento, para devolver los valores actualizados de las columnas modificadas en el servidor.&lt;/div&gt;&lt;div&gt;Evidentemente, el uso de procedimientos almacenados para estas operaciones requiere un poco más de planificación por parte del programador... pero es una tarea mecanizable, y seguramente podremos contar con la ayuda del DBA. Tenga en cuenta que el DBA no protestará si le pide que no permita actualizaciones en una tabla excepto a través de un procedimiento almacenado: estas cosas hacen feliz a un administrador de bases de datos.&lt;/div&gt;&lt;div&gt;Es poco probable que una aplicación en dos capas, para la que se presume poca carga, se beneficie de un mecanismo tan sofisticado de actualización. Pero en una aplicación multicapas con mucha carga, cada milisegundo (¡sí, hablo de milisegundos!) que se gane en una operación, significa más capacidad de concurrencia para la capa intermedia: el modelo de concurrencia de una capa intermedia con &lt;i&gt;pooling&lt;/i&gt; no ofrece capacidad lineal respecto a los tiempos de respuesta. El truco de combinar &lt;i&gt;UpdateBatchSize&lt;/i&gt; con procedimientos almacenados puede parecer excesivamente complicado a algunos, pero es bueno saber que disponemos de un arma como ésta en nuestro arsenal.&lt;/div&gt;&lt;hr class="p"&gt;&lt;div&gt;&lt;span class="first"&gt;&lt;b&gt;Actualización:&lt;/b&gt; He subido una pequeña&lt;/span&gt; actualización de &lt;a href="http://www.marteens.com/pdfs/csharp_intsight.pdf" target="_blank"&gt;Intuitive C#&lt;/a&gt;, con una nueva sección sobre métodos de extensión. Lo único interesante es que he añadido la sección al capítulo de interfaces.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-4757611766489710574?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/4757611766489710574/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=4757611766489710574&amp;isPopup=true' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/4757611766489710574'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/4757611766489710574'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/01/updatebatchsize.html' title='UpdateBatchSize'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_QWaXq7W8dVI/R3_c4_rSXTI/AAAAAAAAAHA/9saMmk4K8Kk/s72-c/parade.jpg' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-5134845878579499062</id><published>2008-01-03T23:34:00.000+01:00</published><updated>2008-12-11T09:01:32.625+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Freya'/><category scheme='http://www.blogger.com/atom/ns#' term='optimización'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><title type='text'>El objeto activo</title><content type='html'>&lt;div&gt;&lt;span class="first"&gt;¿Qué se supone que tiene&lt;/span&gt; que pasar cuando se ejecute este código?&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;using&lt;/b&gt; System;&lt;br /&gt;&lt;b&gt;public&lt;/b&gt;&lt;br /&gt;    &lt;font class="teal"&gt;Program&lt;/font&gt; = &lt;b&gt;class&lt;/b&gt;&lt;br /&gt;    &lt;b&gt;public&lt;/b&gt;&lt;br /&gt;        &lt;b&gt;method&lt;/b&gt; Test: &lt;font color="teal"&gt;Boolean&lt;/font&gt; =&amp;gt; Self &amp;lt;&amp;gt; &lt;b&gt;nil&lt;/b&gt;;&lt;/pre&gt;&lt;pre class="p" style="margin-top: 6px;"&gt;        &lt;b&gt;static method&lt;/b&gt; Main;&lt;br /&gt;        &lt;b&gt;begin&lt;/b&gt;&lt;br /&gt;            &lt;b&gt;var&lt;/b&gt; Instance: &lt;font color="teal"&gt;Program&lt;/font&gt; := &lt;b&gt;nil&lt;/b&gt;;&lt;br /&gt;            &lt;font color="teal"&gt;Console&lt;/font&gt;.WriteLine(Instance.Test);&lt;br /&gt;        &lt;b&gt;end&lt;/b&gt;;&lt;br /&gt;    &lt;b&gt;end&lt;/b&gt;&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;&lt;/pre&gt;&lt;hr class="p"&gt;&lt;div&gt;&lt;img style="float:right; margin:1px 0 1px 8px;border-style:none;padding:0px;" src="http://2.bp.blogspot.com/_QWaXq7W8dVI/R35cr_rSXQI/AAAAAAAAAGo/V61RK4hhEP8/s320/gun.jpg" border="0" alt="Janie's got a gun" /&gt;&lt;span class="first"&gt;La respuesta breve es&lt;/span&gt; que se imprimirá &lt;i&gt;False&lt;/i&gt;.&lt;/div&gt;&lt;div&gt;La respuesta larga tiene que ver con uno de los objetivos de Freya: experimentar con la eficiencia del lenguaje, y en este caso, entra en escena el código IL que se genera para la llamada a un procedimiento. Hay dos de estos códigos: &lt;b&gt;call&lt;/b&gt; y &lt;b&gt;callvirt&lt;/b&gt;. El segundo de ellos se utiliza, evidentemente, para ejecutar métodos virtuales, pero curiosamente, también puede ocuparse de métodos no virtuales, como es el caso de nuestro método &lt;i&gt;Test&lt;/i&gt;. En tal caso, la diferencia respecto a &lt;b&gt;call&lt;/b&gt; es que, al generarse el código nativo final, &lt;b&gt;callvirt&lt;/b&gt; añade una verificación del puntero de instancia. Si este es nulo, excepción al canto.&lt;/div&gt;&lt;div&gt;Resulta que &lt;b&gt;callvirt&lt;/b&gt; es utilizado deliberadamente por C&lt;sup&gt;#&lt;/sup&gt; para casi todas las llamadas a métodos de instancia, sean virtuales o no. Esta es la forma de satisfacer la especificación del lenguaje, que exige que rueden cabezas si se pasa un nulo como objeto activo a un método de instancias. Es también interesante que, en contadas ocasiones, C&lt;sup&gt;#&lt;/sup&gt; puede optimizar la llamada si sabe a ciencia cierta que el puntero no será nulo. ¿Cuándo puede tener esta certeza? Por ejemplo, cuando el objeto pasado se acaba de construir. Un método ejecutado sobre una expresión &lt;b&gt;new&lt;/b&gt; no necesita esta verificación.&lt;/div&gt;&lt;div&gt;Freya, por el contrario, siempre usa &lt;b&gt;call&lt;/b&gt; para métodos no virtuales, con lo que logra una ganancia en velocidad mínima, pero notable, sobre C&lt;sup&gt;#&lt;/sup&gt;. Hay una ganancia también en el tamaño del código nativo, que se traduce en un uso más eficiente de la memoria, y a la larga, en más velocidad: la comprobación de no nulidad la ejecuta quien llama, por lo que se repite innumerables veces a lo largo del código. El coste: la especificación de Freya no exige que la instancia activa sea no nula. De ahí que tengan sentido ejemplos como el mostrado.&lt;/div&gt;&lt;div&gt;La pregunta es, naturalmente, si es peligrosa esta "relajación". No lo es, por supuesto:&lt;/div&gt;&lt;ol&gt;&lt;li&gt;Si se pasa una referencia nula como objeto activo a un método que no lo permite, la excepción se va a producir, de todos modos, en cuanto el objeto activo intente tocar algún campo o método de instancia. Es decir: el error se detectará, aunque algo más tarde.&lt;/li&gt;&lt;li&gt;En realidad, la no nulidad del objeto activo puede verse como una precondición en el contrato del método, en los lenguajes que la exigen: se supone que el software correctamente escrito nunca violará la precondición. Pero en ese caso, si en el software final se mantiene la verificación, ¡estaremos comprobando una y otra vez si se produce lo imposible!&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;A mediano plazo, Freya deberá incorporar aserciones especiales sobre la nulidad de campos y parámetros. Esto traerá algunas novedades interesantes al lenguaje. Piense un momento: si digo que el campo &lt;i&gt;C&lt;/i&gt;, de tipo &lt;i&gt;Object&lt;/i&gt;, no puede ser nulo, ¿cómo vamos a tratar el hecho de que el CLR lo inicialice precisamente como nulo? La clave está en añadir &lt;i&gt;inicializadores de campos&lt;/i&gt; a los constructores, al estilo C++:&lt;/div&gt;&lt;pre class="p"&gt;&lt;i&gt;// En una clase Stack[X]...&lt;/i&gt;&lt;br /&gt;&lt;b&gt;constructor&lt;/b&gt;(Capacity: Integer) :&lt;br /&gt;    Items(&lt;b&gt;new&lt;/b&gt; &lt;font color="teal"&gt;Array&lt;/font&gt;[X](Capacity)),&lt;br /&gt;    Inherited&lt;br /&gt;&lt;b&gt;begin&lt;br /&gt;end&lt;/b&gt;;&lt;/pre&gt;&lt;div&gt;El CLR permite que estas inicializaciones de campos se ejecuten incluso antes de la llamada al constructor de la clase base: es así, de hecho, como se ejecutan los actuales inicializadores de campos de C&lt;sup&gt;#&lt;/sup&gt; y Freya. La diferencia es que, con el nuevo recurso, los inicializadores de campos podrán utilizar los parámetros del constructor, algo que ahora mismo es imposible.&lt;/div&gt;&lt;div&gt;Por cierto, el último listado puede abreviarse a lo siguiente:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;constructor&lt;/b&gt;(Capacity: Integer) :&lt;br /&gt;    Items(&lt;b&gt;new&lt;/b&gt; &lt;font color="teal"&gt;Array&lt;/font&gt;[X](Capacity));&lt;/pre&gt;&lt;div&gt;La llamada al constructor por omisión heredado se asume, y el bloque de instrucciones, al estar vacío, se puede omitir. Un constructor paralelo, sin parámetros, se programa en Freya de este modo:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;constructor&lt;/b&gt; : Self(128);&lt;/pre&gt;&lt;div&gt;Las instancias especiales &lt;b&gt;base&lt;/b&gt; y &lt;b&gt;this&lt;/b&gt; de C&lt;sup&gt;#&lt;/sup&gt; se sustituyen en Freya por los identificadores especiales &lt;i&gt;Inherited&lt;/i&gt; y &lt;i&gt;Self&lt;/i&gt;.&lt;/div&gt;&lt;hr class="p"&gt;&lt;div&gt;... quien haya depurado una aplicación .NET en código nativo, se habrá encontrado con instrucciones aparentemente absurdas como ésta, justo antes de una llamada a rutina:&lt;/div&gt;&lt;pre class="p"&gt;cmp byte ptr [rax],0&lt;/pre&gt;&lt;div&gt;Se trata de la verificación de no nulidad, en este caso, en código de 64 bits. En un procesador de 32 bits, he visto esta variante:&lt;/div&gt;&lt;pre class="p"&gt;cmp byte ptr [eax],eax&lt;/pre&gt;&lt;div&gt;Al parecer, la diferencia debe estar en el tamaño de ambas instrucciones. Pero en ambos casos, el principio es el mismo: si EAX o RAX tienen un puntero no nulo, la instrucción hará una comparación rápida e inofensiva. En caso contrario, la memoria a la que apunta el registro estará en la zona prohibida, y el propio procesador levantará la liebre... quiero decir, la excepción.&lt;/div&gt;&lt;hr class="p" /&gt;&lt;div&gt;Por último, la posibilidad de simular el traspaso de un objeto activo nulo la dan los métodos de extensión:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;public static class&lt;/b&gt; &lt;font color="teal"&gt;StringExtender&lt;/font&gt;&lt;br /&gt;{&lt;br /&gt;    &lt;b&gt;public static bool&lt;/b&gt; IsEmpty(&lt;b&gt;this string&lt;/b&gt; s)&lt;br /&gt;    {&lt;br /&gt;        &lt;b&gt;return string&lt;/b&gt;.IsNullOrEmpty(s);&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;div&gt;Si se puede lograr por medio de métodos de extensión, ¿qué hay de malo en permitirlo para los métodos de instancia?&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-5134845878579499062?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/5134845878579499062/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=5134845878579499062&amp;isPopup=true' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/5134845878579499062'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/5134845878579499062'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2008/01/el-objeto-activo.html' title='El objeto activo'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_QWaXq7W8dVI/R35cr_rSXQI/AAAAAAAAAGo/V61RK4hhEP8/s72-c/gun.jpg' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-7838383569518981656</id><published>2007-12-31T16:49:00.000+01:00</published><updated>2008-12-11T09:01:32.927+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Freya'/><category scheme='http://www.blogger.com/atom/ns#' term='ideas'/><category scheme='http://www.blogger.com/atom/ns#' term='extension methods'/><category scheme='http://www.blogger.com/atom/ns#' term='interface'/><title type='text'>Ornitorrinco</title><content type='html'>&lt;div&gt;&lt;img style="float:right; margin:0 0 10px 10px; border-style:none; padding: 0px;" src="http://2.bp.blogspot.com/_QWaXq7W8dVI/R3kPjPrSXPI/AAAAAAAAAGg/-A6HV1n3UqA/s320/ornie.jpg" border="0" alt="... and the mome raths outgrabe." /&gt;&lt;span class="first"&gt;No todo lo que&lt;/span&gt; camina como un pato, nada como un pato y pone huevos como un pato, tiene necesariamente que ser un pato. Podría tratarse de un ornitorrinco, ¿verdad?&lt;/div&gt;&lt;div&gt;Suponga que yo le digo que esto es Freya:&lt;/div&gt;&lt;pre class="p"&gt;&lt;font color="teal"&gt;IStack&lt;/font&gt; = &lt;b&gt;interface&lt;/b&gt;[X]&lt;br /&gt;    Count: &lt;font color="teal"&gt;Integer&lt;/font&gt;;&lt;br /&gt;    Top: X;&lt;br /&gt;    &lt;b&gt;method&lt;/b&gt; Push(Value: X);&lt;br /&gt;    &lt;b&gt;method&lt;/b&gt; Pop;&lt;br /&gt;        &lt;b&gt;requires&lt;/b&gt; Count &gt; 0;&lt;/pre&gt;&lt;pre class="p" style="margin-top: 0;"&gt;    IsEmpty: &lt;font color="teal"&gt;Boolean&lt;/font&gt; =&amp;gt; Count = 0;&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;;&lt;/pre&gt;&lt;div&gt;Para que le resulte más fácil detectar el elemento &lt;i&gt;extraño&lt;/i&gt;, utilizaré una sintaxis equivalente, algo más verbosa:&lt;/div&gt;&lt;pre class="p"&gt;&lt;font color="teal"&gt;IStack&lt;/font&gt; = &lt;b&gt;interface&lt;/b&gt;[X]&lt;br /&gt;    &lt;b&gt;property&lt;/b&gt; Count: &lt;font color="teal"&gt;Integer&lt;/font&gt;;&lt;br /&gt;    &lt;b&gt;property&lt;/b&gt; Top: X;&lt;br /&gt;    &lt;b&gt;method&lt;/b&gt; Push(Value: X);&lt;br /&gt;    &lt;b&gt;method&lt;/b&gt; Pop;&lt;br /&gt;        &lt;b&gt;requires&lt;/b&gt; Count &gt; 0;&lt;/pre&gt;&lt;pre class="p" style="margin-top: 0;"&gt;    &lt;b&gt;property&lt;/b&gt; IsEmpty: &lt;font color="teal"&gt;Boolean&lt;/font&gt;;&lt;br /&gt;    &lt;b&gt;begin&lt;/b&gt;&lt;br /&gt;        Result := Count = 0;&lt;br /&gt;    &lt;b&gt;end&lt;/b&gt;;&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;;&lt;/pre&gt;&lt;div&gt;Y ahora, antes de subir la otra mitad del artículo, dígame si lo anterior le parece bien o mal...&lt;/div&gt;&lt;hr class="p"&gt;&lt;div&gt;Efectivamente, como mencionaba Marto en un comentario, se supone que las interfaces no "implementan". Sin embargo, es precisamente ese efecto lo que logran los &lt;i&gt;métodos de extensión&lt;/i&gt; de C&lt;sup&gt;#&lt;/sup&gt; 3.0:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;interface&lt;/b&gt; &lt;font color="teal"&gt;IStack&lt;/font&gt;&amp;lt;X&amp;gt;&lt;br /&gt;{&lt;br /&gt;    &lt;b&gt;int&lt;/b&gt; Count { &lt;b&gt;get&lt;/b&gt;; }&lt;br /&gt;    X Top { &lt;b&gt;get&lt;/b&gt;; }&lt;br /&gt;    &lt;b&gt;void&lt;/b&gt; Push(X value);&lt;br /&gt;    &lt;b&gt;void&lt;/b&gt; Pop();&lt;br /&gt;}&lt;/pre&gt;&lt;pre class="p" style="margin-top: 0;"&gt;&lt;b&gt;static class&lt;/b&gt; &lt;font color="teal"&gt;StackExt&lt;/font&gt;&lt;br /&gt;{&lt;br /&gt;    &lt;b&gt;public static bool&lt;/b&gt; IsEmpty&amp;lt;X&amp;gt;(&lt;b&gt;this&lt;/b&gt; &lt;font color="teal"&gt;IStack&lt;/font&gt;&amp;lt;X&amp;gt; s)&lt;br /&gt;    {&lt;br /&gt;        &lt;b&gt;return&lt;/b&gt; s.Count == 0;&lt;br /&gt;    }&lt;br /&gt;}&lt;/pre&gt;&lt;div&gt;Gracias a estos métodos, es posible escribir código como el siguiente, suponiendo que tenemos ya una clase que implementa el tipo de interfaz:&lt;/div&gt;&lt;pre class="p"&gt;&lt;font color="teal"&gt;IStack&lt;/font&gt;&amp;lt;&lt;b&gt;int&lt;/b&gt;&amp;gt; st = &lt;b&gt;new&lt;/b&gt; &lt;font color="teal"&gt;StackImpl&lt;/font&gt;&amp;lt;&lt;b&gt;int&lt;/b&gt;&amp;gt;();&lt;br /&gt;&lt;b&gt;if&lt;/b&gt; (st.IsEmpty()) { ... }&lt;/pre&gt;&lt;div&gt;¿Es bueno, o es malo? No veo nada malo en permitir manipulaciones predefinidas sobre el estado "público" ofrecido por el contrato de la interfaz: lo mismo se puede lograr, incluso sin métodos de extensión, aunque al precio de escribir muchísimo más.&lt;/div&gt;&lt;div&gt;Ahora bien, mi duda va más allá. ¿Merece la pena implementar métodos de extensión (Freya ya los tiene), o sería suficiente con añadir al lenguaje implementaciones predefinidas en interfaces, como la del ejemplo de Freya? El caso es que los métodos de extensión son nada elegantes:&lt;/div&gt;&lt;ul&gt;&lt;li&gt;El mecanismo de selección es horrible: basta con introducir una cláusula &lt;b&gt;using&lt;/b&gt; para activarlos, dándole un protagonismo inapropiado a estas cláusulas.&lt;/li&gt;&lt;li&gt;Estos métodos, cuando se emplean para extender una clase, plantean un grave problema de estabilidad respecto al versionado: si el implementador de la clase introduce un método de instancia en la clase extendida, dejará de funcionar la extensión, porque el método de instancia tiene la prioridad. Lo peor es que sería muy difícil detectar estos problemas.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;De momento, a falta de más análisis, me inclino por sustituir este recurso por implementaciones en interfaces. Es verdad que no son recursos equivalentes, pero la suciedad de los métodos de extensión me aterra.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-7838383569518981656?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/7838383569518981656/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=7838383569518981656&amp;isPopup=true' title='6 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7838383569518981656'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7838383569518981656'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/12/ornitorrinco.html' title='Ornitorrinco'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_QWaXq7W8dVI/R3kPjPrSXPI/AAAAAAAAAGg/-A6HV1n3UqA/s72-c/ornie.jpg' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-1363151766141992716</id><published>2007-12-30T17:35:00.000+01:00</published><updated>2008-12-11T09:01:33.109+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><category scheme='http://www.blogger.com/atom/ns#' term='SQL'/><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>Vade retro, LINQ pro SQL</title><content type='html'>&lt;div&gt;&lt;span class="first"&gt;Hágame caso, y evitará&lt;/span&gt; malgastar sus fuerzas: si quiere desarrollar una aplicación seria, &lt;b&gt;apártese de LINQ para SQL&lt;/b&gt;. Al menos, de momento...&lt;/div&gt;&lt;div&gt;Llevo varios días descubriendo cosas que no me gustan, pero me he contenido por prudencia. El descubrimiento que ha puesto el último clavo sobre el ataúd del invento tiene que ver con la forma en que se manejan las relaciones maestro/detalles. Pongamos por caso que tenemos dos tablas relacionadas, como &lt;em&gt;Clientes&lt;/em&gt; y &lt;em&gt;Pedidos&lt;/em&gt;:&lt;/div&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center; border-style:none" src="http://2.bp.blogspot.com/_QWaXq7W8dVI/R3fL3vrSXOI/AAAAAAAAAGY/vgwcbtMz1GQ/s320/mdlinq.jpg" border="0" alt="" /&gt;&lt;div&gt;LINQ para SQL crea dos clases, con un formato predecible:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;public partial class&lt;/b&gt; &lt;font color="teal"&gt;Customer&lt;/font&gt;&lt;br /&gt;{&lt;br /&gt;    &lt;b&gt;public&lt;/b&gt; &lt;font color="teal"&gt;EntitySet&lt;/font&gt;&amp;lt;&lt;font color="teal"&gt;Order&lt;/font&gt;&amp;gt; Orders { ... }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;b&gt;public partial class&lt;/b&gt; &lt;font color="teal"&gt;Order&lt;/font&gt;&lt;br /&gt;{&lt;br /&gt;    &lt;b&gt;public&lt;/b&gt; &lt;font color="teal"&gt;Customer&lt;/font&gt; Customer { ... }&lt;br /&gt;}&lt;/pre&gt;&lt;div&gt;¿En qué momento se leen los pedidos de un cliente? Por omisión, no cuando se crea el cliente; ni siquiera cuando se accede a la propiedad &lt;i&gt;Orders&lt;/i&gt;. Hay que intentar hacer algo con el &lt;i&gt;contenido&lt;/i&gt; de la colección para que se dispare la consulta SQL correspondiente, que se parecerá a la siguiente:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;select&lt;/b&gt; * &lt;b&gt;from&lt;/b&gt; orders&lt;br /&gt;&lt;b&gt;where&lt;/b&gt; CustomerID = @CustomerID&lt;/pre&gt;&lt;div&gt;Hasta aquí, todo es esperable, predecible y aceptable... suponiendo que estamos creando una aplicación con la vetusta arquitectura cliente/servidor. Si vamos a tener cuatro gatos conectados a un servidor local de SQL Server (pues LINQ para SQL sólo soporta, de momento, SQL Server), las cosas nos irán bien. Pero para eso no hacía falta gastar dinero en una subscripción anual a la MSDN. Cómprese un Delphi 7 de segunda o tercera mano, o incluso un Visual Basic "clásico", y sea feliz.&lt;/div&gt;&lt;div&gt;Pero, ¿qué pasa con la programación &lt;i&gt;seria&lt;/i&gt;? Cuando usted se trae los datos de un grupo de clientes a la capa de presentación, tiene dos opciones, teóricamente: la carga incremental, o por demanda, de sus pedidos, o traer todos los pedidos en la misma operación que trae el grupo de clientes. En mi libro particular de estilo, la carga "por demanda" no sería aceptable. Cuando alguien pide &lt;i&gt;clientes y sus pedidos&lt;/i&gt;, es porque realmente necesita ambas entidades, y en programación multicapas, el pecado mortal de necesidad se llama &lt;i&gt;round-trip&lt;/i&gt;; es decir, viaje de ida y vuelta al servidor de capa intermedia. Pero mantengamos las opciones abiertas, y supongamos que cada técnica tiene su uso. Pues bien:&lt;/div&gt;&lt;ol&gt;&lt;li&gt;LINQ para SQL no permite implementar la carga por demanda cuando hay una capa intermedia. Para transmitir un registro de cliente, hay que "serializarlo", y eso implica serializar sus pedidos. Adiós lectura incremental de los pedidos.&lt;/li&gt;&lt;li&gt;Y ahora viene lo peor: supongamos que ya estamos resignados a no usar la carga por demanda. El caso es que LINQ para SQL implementa la lectura, en esos casos, de manera asquerosamente ineficiente.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;Aquí aparecerá el listo de siempre, que alegará la existencia de unas &lt;i&gt;DataLoadOptions&lt;/i&gt; que permitirían desactivar la carga por demanda. En efecto, LINQ para SQL ofrece algo así:&lt;/div&gt;&lt;pre class="p"&gt;&lt;font color="teal"&gt;DataLoadOptions&lt;/font&gt; dlo = &lt;b&gt;new&lt;/b&gt; &lt;font color="teal"&gt;DataLoadOptions&lt;/font&gt;();&lt;br /&gt;dlo.LoadWith&amp;lt;&lt;font color="teal"&gt;Customer&lt;/font&gt;&amp;gt;(c =&amp;gt; c.Orders);&lt;br /&gt;dataContext.LoadOptions = dlo;&lt;/pre&gt;&lt;div&gt;Pero, si se molestase en comprobar qué es lo que realmente hace dicha opción, comprobaría que, si se leen cuatrocientos clientes, esta opción provocaría que el servidor de capa intermedia lanzase otras cuatrocientos consultas SQL para leer individualmente los pedidos de cada cliente. Sí, es verdad que esta avalancha se produciría de golpe, en vez de incrementalmente...&lt;/div&gt;&lt;div&gt;Las cosas son buenas o malas en comparación con otras. ¿Cómo se resuelve este problema en ADO.NET con los conjuntos de datos de toda la vida? Muy simple: usted sólo necesita lanzar dos consultas, y es ADO.NET quien se encarga de tejer la relación en memoria, una vez que dispone de todos los registros. ¿Quiere, por ejemplo, los clientes de Madrid y sus pedidos? En un mismo comando (¡para ahorrar aún más!) se incluirían dos consultas:&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;select&lt;/b&gt; * &lt;b&gt;from&lt;/b&gt; Customers&lt;br /&gt;&lt;b&gt;where&lt;/b&gt; City = "Madrid";&lt;br /&gt;&lt;b&gt;select&lt;/b&gt; * &lt;b&gt;from&lt;/b&gt; Orders&lt;br /&gt;&lt;b&gt;where&lt;/b&gt; CustomerID &lt;b&gt;in&lt;/b&gt; (&lt;br /&gt;    &lt;b&gt;select&lt;/b&gt; CustomerID &lt;b&gt;from&lt;/b&gt; Customers&lt;br /&gt;    &lt;b&gt;where&lt;/b&gt; City = "Madrid")&lt;/pre&gt;&lt;div&gt;A SQL Server se le da muy bien responder a este tipo de consultas, a pesar de su aparente complejidad. Y no le digo nada sobre recuperar los clientes que hicieron pedidos la semana anterior: la ganancia comparativa sería escandalosa.&lt;/div&gt;&lt;div&gt;¿Conclusión? Pues que LINQ para SQL &lt;b&gt;no está preparado para la vida real&lt;/b&gt;. Es un juguetito con ínfulas, que a la hora de la verdad se queda muy corto... y es lamentable que la comunidad de programadores no esté diciéndolo en voz alta. No se trata sólo del problema aquí explicado: hay que sumar los problemas que ya la propia Microsoft explica para el funcionamiento del sistema en tres capas. Por ejemplo: los valores originales de cada registro se almacenan en el contexto, y al serializar un registro se pierden, no existe una funcionalidad comparable al &lt;i&gt;Merge&lt;/i&gt; de los conjuntos de datos...&lt;/div&gt;&lt;div&gt;Es cierto que Microsoft se reserva eso del &lt;i&gt;ADO.NET Entity Framework&lt;/i&gt; para febrero o marzo (es significativo que hayan publicado Visual Studio 2008 sin esperar por él). Habrá que esperar al producto final antes pronunciarse. Pero cada vez creo menos en la bondad de los ORMs: tengo razones para esperar muy poco de este tipo de sistemas. De todos modos, seré prudente: ya veremos qué tal se comporta el nuevo invento. A lo mejor esta es la vez en que un ORM acierta por primera vez en la Historia...&lt;/div&gt;&lt;hr style="border-style:dotted; border-color: #C0C0E0; height:1px;" /&gt;&lt;div&gt;... y que ahora alguien me diga cuál es la urgencia para aprender a usar LINQ. ¿Para aplicarlo al famoso LINQ para SQL?&lt;/div&gt;&lt;div&gt;Mucho cuidado: no estoy diciendo que no merezca pasarse a VS2008. Todo lo contrario, &lt;b&gt;¡pásese urgentemente a la nueva versión!&lt;/b&gt; Hay suficientes mejoras como para merecer la pena, y la principal de ellas, en mi humilde opinión, es la nueva técnica de generación de clases para conjuntos de datos, que facilita enormemente la creación de aplicaciones en tres capas.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-1363151766141992716?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/1363151766141992716/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=1363151766141992716&amp;isPopup=true' title='54 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/1363151766141992716'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/1363151766141992716'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/12/vade-retro-linq-pro-sql.html' title='Vade retro, LINQ pro SQL'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_QWaXq7W8dVI/R3fL3vrSXOI/AAAAAAAAAGY/vgwcbtMz1GQ/s72-c/mdlinq.jpg' height='72' width='72'/><thr:total>54</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-7773291205836404785</id><published>2007-12-27T16:56:00.000+01:00</published><updated>2007-12-28T12:07:02.369+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><title type='text'>Novedades en Visual Studio 2008</title><content type='html'>&lt;div&gt;&lt;span class="first"&gt;Era un poco extenso&lt;/span&gt; para colgarlo de la bitácora:&lt;/div&gt;&lt;ul type="square"&gt;&lt;li&gt;&lt;a href="http://www.marteens.com/trick5D.htm" target="_blank"&gt;Novedades en el acceso a datos con VS2008&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Se trata, más bien, de los cambios que simplifican las aplicaciones del curso de ADO.NET. Son pocos, pero interesantes.&lt;/div&gt;&lt;hr style="border-style:dotted; border-color: #C0C0E0; height:1px;" /&gt;&lt;div&gt;Por cierto, ¡qué "divertido" es programar con Java! Acabo de darme cuenta de que Java no tiene mecanismos para la solución de conflictos de nombre al implementar interfaces. En C&lt;sup&gt;#&lt;/sup&gt; se utilizan las implementaciones explícitas para este fin. Y en Delphi existía un mecanismo parecido.&lt;/div&gt;&lt;div&gt;En particular, me gusta usar implementaciones explícita cuando quiero evitar que alguien (casi siempre, yo mismo), accidentalmente, acceda a un método o una propiedad a través de la clase, en vez de usar el tipo de interfaz. La experiencia me dice que introduce menos dependencias el uso de interfaces que el uso de referencias de clase.&lt;/div&gt;&lt;div&gt;Naturalmente, he añadido el "detalle" a &lt;a href="http://www.marteens.com/trick5c.htm#expimp" target="_blank"&gt;uno de los artículos&lt;/a&gt; en mi página que comparan Java con C&lt;sup&gt;#&lt;/sup&gt;.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-7773291205836404785?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/7773291205836404785/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=7773291205836404785&amp;isPopup=true' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7773291205836404785'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7773291205836404785'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/12/novedades-en-visual-studio-2008.html' title='Novedades en Visual Studio 2008'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-4768981489122404516</id><published>2007-12-23T23:15:00.000+01:00</published><updated>2007-12-27T17:01:17.331+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cursos'/><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Disponible: Volumen II, para Visual Studio 2005</title><content type='html'>&lt;div&gt;&lt;span class="first"&gt;Pensé que iba a tardar más&lt;/span&gt; tiempo, pero la migración ha sido sencilla. Ya está disponible el Volumen II (antes, serie D) de nuestro &lt;a href="http://www.intsight.com/cdist05.html" target="_blank"&gt;curso a distancia sobre ADO.NET&lt;/a&gt;, para Visual Studio 2005:&lt;/div&gt;&lt;ul type="square"&gt;&lt;li&gt;&lt;a href="http://www.marteens.com/pdfs/vol1-2.pdf" target="_blank"&gt;Temario combinado: Volúmenes I y II&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Como siempre, las actualizaciones son gratuitas, a través de descargas personalizadas. Si ha usted adquirido el Volumen I en estos días, también le enviaremos el CD "físico" con la actualización, gratis.&lt;/div&gt;&lt;div&gt;Con esta actualización, el curso completo está disponible para Visual Studio 2005. Seguimos incluyendo en el CD, no obstante, las versiones de las series A y D para VS2003. Son &lt;b&gt;444 páginas&lt;/b&gt; (566, en realidad, si se cuentan las de Intuitive C#, incluido en el CD), en formato A4, de texto y código sobre desarrollo para .NET. ¿Quién da más?&lt;/div&gt;&lt;h3&gt;¿Y Visual Studio 2008?&lt;/h3&gt;&lt;div&gt;Como ya anuncié, está en preparación una serie sobre &lt;strong&gt;LINQ for SQL&lt;/strong&gt;. Luego se migrarán las series ya disponibles hacia la nueva versión.&lt;/div&gt;&lt;div&gt;Debo advertirle, sin embargo, que los dos volúmenes ya disponibles son completamente &lt;strong&gt;compatibles&lt;/strong&gt; con Visual Studio 2008. De hecho, han sido muy pocos los cambios en la migración de VS2003 a VS2005: la rejilla, el sistema de menúes, y sustituir ciertos usos de &lt;i&gt;DataView&lt;/i&gt; y &lt;i&gt;BindingContext&lt;/i&gt; por el componente &lt;i&gt;BindingSource&lt;/i&gt;, y las diferencias entre VS2005 y VS2008, fuera de LINQ, son muy pocas.&lt;/div&gt;&lt;div&gt;De todos modos, cualquier compra del curso &lt;b&gt;ahora&lt;/b&gt; se considera, a efectos de las actualizaciones, como si se hubiese comprado ya el curso para VS2008, de manera que le queda la actualización gratuita a la versión que venga tras .NET 3.5.&lt;/div&gt;&lt;h3&gt;Combinaciones&lt;/h3&gt;&lt;div&gt;Aunque no he tenido tiempo aún para escribir las reseñas, estamos también comercializando tres nuevos libros sobre .NET:&lt;/div&gt;&lt;ul type="square"&gt;&lt;li&gt;&lt;a href="http://www.marteens.com/pdfs/linqbk.pdf" target="_blank" title="Indice"&gt;C# 3.0 y LINQ&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.marteens.com/pdfs/aspnbk.pdf" target="_blank" title="Indice"&gt;Programación Web con Visual Studio y ASP.NET&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.marteens.com/pdfs/wwfbk.pdf" target="_blank" title="Indice"&gt;Modelando procesos de negocio con Workflow Foundation&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Además de estar disponibles por separado en nuestro &lt;a href="http://www.marteens.com/sales.htm"&gt;catálogo de productos&lt;/a&gt;, es posible también adquirirlos en combinación con cursos y libros nuestros... y beneficiarse de un suculento descuento (en nuestros cursos: la ley española prohibe descuentos a libros por encima del 5%).&lt;/div&gt;&lt;div style="text-align: justify; bottom-margin: 10px;"&gt;Voy a tardar todavía un poco en tener disponibles las reseñas y todos los formularios de combinaciones, pero si está interesado en la posibilidad, contacte conmigo, a través de mi cuenta de correo en IntSight. También enviamos estos libros al extranjero. El coste de envío es similar al de La Cara Oculta de C#, pues cada libro pesa menos de un kilogramo.&lt;/div&gt;&lt;div&gt;&lt;strong&gt;¡Combine y ahorre!&lt;/strong&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-4768981489122404516?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/4768981489122404516/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=4768981489122404516&amp;isPopup=true' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/4768981489122404516'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/4768981489122404516'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/12/disponible-volumen-ii-para-visual.html' title='Disponible: Volumen II, para Visual Studio 2005'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-2270774470486129358</id><published>2007-12-22T20:12:00.001+01:00</published><updated>2007-12-27T17:01:57.868+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cursos'/><category scheme='http://www.blogger.com/atom/ns#' term='Windows Forms'/><title type='text'>Docking en Volumen II</title><content type='html'>&lt;img style="display:block; margin:0px auto 10px; text-align:center;" src="http://www.marteens.com/adv/ej25.jpg" border="0" alt="Pantalla principal del Ejercicio 25/Volumen II" /&gt;&lt;div&gt;&lt;span class="first"&gt;Incluido como "extra", al&lt;/span&gt; final del Volumen II, este ejercicio adapta el &lt;i&gt;layout manager&lt;/i&gt; usado a lo largo de la serie para que, en vez de utilizar ventanas MDI, utilice los componentes de &lt;i&gt;docking&lt;/i&gt; de &lt;a href="http://sourceforge.net/projects/dockpanelsuite" target="_blank"&gt;Weifen Luo&lt;/a&gt; (que dicho sea de paso, también se usan en Blade, el IDE de &lt;a href="http://www.marteens.com/freya" target="_blank"&gt;Freya&lt;/a&gt;).&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-2270774470486129358?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/2270774470486129358/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=2270774470486129358&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2270774470486129358'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2270774470486129358'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/12/docking-en-volumen-ii.html' title='Docking en Volumen II'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-6853460162720741190</id><published>2007-12-18T17:33:00.000+01:00</published><updated>2007-12-21T19:10:37.235+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cursos'/><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><title type='text'>Conciliación en presencia de identidades</title><content type='html'>&lt;div style="text-align: justify; margin-bottom: 6px;"&gt;&lt;span style="font-size: 108%; font-variant: small-caps;"&gt;Copio a continuación un&lt;/span&gt; pequeño fragmento de un ejercicio del Volumen II, para que os hagáis una idea del tipo de problemas prácticos al que se enfrenta una aplicación &lt;i&gt;preparada&lt;/i&gt; para las tres capas, y que tienen que tratarse obligatoriamente como parte de un curso &lt;i&gt;serio&lt;/i&gt; sobre bases de datos.&lt;/div&gt;&lt;div style="padding: 4px 16px 4px 12px; font-size: 90%; background-color: #f0f0f0; clear: both;"&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;img style="float:left; margin:2px 12px 0px 0px; border-style: none; padding: 2px;" src="http://www.marteens.com/adv/vol1_75.jpg" border="0" alt="Programación con ADO.NET en C# - Volúmenes I y II" /&gt;La implementación que hemos proporcionado a &lt;i&gt;SaveChanges&lt;/i&gt; es mínima, y no es difícil encontrar casos para los que tendremos que complicarla. El primer ejemplo: la inserción de registros en tablas que contienen columnas con el atributo &lt;b&gt;identity&lt;/b&gt;. De hecho, todas nuestras tablas tienen como clave primaria una columna con dicho atributo. Para entender en qué consiste el problema, sigamos el rastro de una inserción de registros. Supongamos que el usuario ha tecleado el siguiente registro para la tabla de países:&lt;/div&gt;&lt;pre style="margin-left: 32px; margin-bottom: 8px; margin-top: 0px; line-height: 110%;"&gt;&amp;lt;  -1, 'PN', 'Polo Norte'... &amp;gt;&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;He puesto –1 como clave primaria del nuevo registro, para evitar confusiones. Supondremos que este valor ha sido asignado automáticamente en el lado cliente. No obstante, al grabar el registro, el algoritmo de grabación recupera el valor asignado a la clave por el servidor. Este sería el estado del registro una vez insertado y actualizado:&lt;/div&gt;&lt;pre style="margin-left: 32px; margin-bottom: 8px; margin-top: 0px; line-height: 110%;"&gt;&amp;lt;1234, 'PN', 'Polo Norte'... &amp;gt;&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Recuerde, sin embargo, que la grabación se ejecuta sobre un conjunto de datos auxiliar que sólo contiene las filas con algún tipo de cambio. Para que el conjunto de datos original se actualice, tenemos que ejecutar la operación &lt;i&gt;Merge&lt;/i&gt;. Este método utiliza las claves primarias para identificar los registros originales con sus copias más recientes. Y esto es un problema, precisamente porque la clave primaria ha sido modificada durante la inserción. Después de ejecutar &lt;i&gt;Merge&lt;/i&gt; tendríamos dos copias del mismo registro, con valores diferentes en la clave primaria:&lt;/div&gt;&lt;pre style="margin-left: 32px; margin-bottom: 8px; margin-top: 0px; line-height: 110%;"&gt;&amp;lt;  -1, 'PN', 'Polo Norte'... &amp;gt;&lt;br /&gt;&amp;lt;1234, 'PN', 'Polo Norte'... &amp;gt;&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;¿Se da cuenta de que nos sobra el primero de los registros? Para evitar esta duplicación de las inserciones, tendríamos que eliminar los registros añadidos al conjunto de datos original antes de mezclar el contenido de delta. Esta es una versión más completa de &lt;i&gt;SaveChanges&lt;/i&gt;:&lt;/div&gt;&lt;pre style="margin-left: 32px; margin-bottom: 8px; margin-top: 0px; line-height: 110%;"&gt;&lt;b&gt;public virtual bool&lt;/b&gt; SaveChanges()&lt;br /&gt;{&lt;br /&gt;  &lt;font color="teal"&gt;DataSet&lt;/font&gt; delta = &lt;font color="teal"&gt;Data&lt;/font&gt;.Instance.Write(&lt;br /&gt;    dataset.DataSetName, dataset.GetChanges());&lt;br /&gt;  &lt;b&gt;foreach&lt;/b&gt; (&lt;font color="teal"&gt;DataTable&lt;/font&gt; tab &lt;b&gt;in&lt;/b&gt; dataset.Tables)&lt;br /&gt;  {&lt;br /&gt;    &lt;b&gt;foreach&lt;/b&gt; (&lt;font color="teal"&gt;DataRow&lt;/font&gt; row &lt;b&gt;in&lt;/b&gt; tab.Select(&lt;br /&gt;      &lt;b&gt;null&lt;/b&gt;, &lt;b&gt;null&lt;/b&gt;, &lt;font color="teal"&gt;DataViewRowState&lt;/font&gt;.Added))&lt;br /&gt;    {&lt;br /&gt;      row.Delete();&lt;br /&gt;    }&lt;br /&gt;  }&lt;br /&gt;  dataset.Merge(delta, &lt;b&gt;false&lt;/b&gt;);&lt;br /&gt;  dataset.AcceptChanges();&lt;br /&gt;  &lt;b&gt;return true&lt;/b&gt;;&lt;br /&gt;}&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 4px;"&gt;No importa si alguna tabla no utiliza el atributo de identidad. Si borramos una fila añadida dentro del conjunto de datos original, de todos modos volveremos a incorporarla al mezclar el delta. Observe que, para cada tabla, detectamos los registros añadidos gracias a su estado, aplicando el método &lt;i&gt;Select&lt;/i&gt; a la tabla.&lt;/div&gt;&lt;/div&gt;&lt;div style="text-align: justify; margin-bottom: 10px;"&gt;Naturalmente, el código que hay que incluir para resolver estos problemas eminentemente prácticos no siempre es sencillo o evidente. De ahí la dificultad de escribir un curso de ADO.NET &lt;i&gt;verdaderamente útil&lt;/i&gt;, y mi decisión de mantener la línea argumental del actual curso en su actualización.&lt;/div&gt;&lt;hr style="border-style:dotted; border-color: #C0C0E0; height:1px;" /&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;&lt;b&gt;Actualización&lt;/b&gt;: Para Navidad, actualización de la serie D a VS2005...&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-6853460162720741190?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/6853460162720741190/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=6853460162720741190&amp;isPopup=true' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/6853460162720741190'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/6853460162720741190'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/12/conciliacin-en-presencia-de-identidades.html' title='Conciliación en presencia de identidades'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-7284376213441832201</id><published>2007-12-16T17:57:00.000+01:00</published><updated>2008-12-11T09:01:33.381+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cursos'/><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='remoting'/><title type='text'>La maldita serie D</title><content type='html'>&lt;div align="justify" style="margin-bottom: 10px;"&gt;&lt;img style="float:left; margin:4px 8px 1px 0px;padding:0px;border-style:none;" src="http://4.bp.blogspot.com/_QWaXq7W8dVI/R2VdIvrSXNI/AAAAAAAAAGQ/D01AG811vno/s320/owl.jpg" border="0" alt="" /&gt;&lt;span style="font-size: 108%; font-variant: small-caps;"&gt;Me he puesto a migrar&lt;/span&gt;, en paralelo con la escritura de la serie sobre &lt;b&gt;LINQ for SQL&lt;/b&gt;, la vieja serie D. Es relativamente fácil adaptar los ejercicios, incluso a Visual Studio 2008. En tres días he adelantado tanto como el ejercicio 10 (de 24 ejercicios en total). Y entonces me he dado cuenta del problema.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;La línea de razonamiento y el desarrollo del curso son estupendos, pero parten de una premisa: el estudiante está interesado en aplicaciones multicapas, y está, además, convencido de la necesidad de las mismas. Por eso, supuse yo al escribir el original, aceptaría el uso de la compleja infraestructura que se desarrolla en el curso. En la práctica, supongo que lo más frecuente es que, quien lee los ejercicios, se pregunte si todo eso tiene que ser tan complicado, por necesidad, o si se trata de fuegos de artificio del autor, que intenta demostrar lo mucho que sabe.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;Para que se comprenda lo que digo, aquí va un ejemplo concreto:&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Normalmente, una grabación de los cambios en un conjunto de datos se resuelve en ADO.NET con una simple llamada al método &lt;i&gt;Update&lt;/i&gt; de un adaptador, una sucesión de llamadas de este tipo, o el código equivalente, si se usan los adaptadores de tablas.&lt;/li&gt;&lt;li&gt;En cambio, en mi curso se añade código para eliminar filas insertadas en el conjunto de datos. Y si no se ha seguido la línea del curso, uno de repente se pregunta: ¿y por qué? Bueno, porque en mi curso la actualización no tiene lugar directamente sobre el conjunto de datos conectado a la rejilla, sino sobre una copia del mismo enviada a un servidor de capa intermedia. La famosa y sencilla llamada a &lt;i&gt;Update&lt;/i&gt; transcurre allí, y lo que el estudiante tiene que aprender es a sincronizar el conjunto de datos modificado con los registros originales. Es una tarea típica de la programación multicapas.&lt;/li&gt;&lt;/ul&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;Ahora me encuentro en una encrucijada. O termino la traducción de lo que hay, o corto por lo sano y saco una serie "práctica" inicial, que no considere la posibilidad de convertir la aplicación en un sistema multicapas. Parecerá absurdo, pero me atrae más esta segunda opción. La nueva división del curso en &lt;strong&gt;Volumen I&lt;/strong&gt; y &lt;strong&gt;Volumen II&lt;/strong&gt; obedece, en definitiva, a un propósito original: mantener dos línea paralelas, una más "teórica" y otra completamente práctica. El Volumen II final podría contener, en su fase final, dos series: la primera, para resolver aplicaciones en dos capas, y la tercera, que se ocupase de los temas específicos de la programación remota, que no tienen que ver tanto con la técnica de &lt;i&gt;remoting&lt;/i&gt; en sí, sino con la sincronización.&lt;/div&gt;&lt;hr style="border-style:dotted; border-color: #C0C0E0; height:1px;" /&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;&lt;strong&gt;Decisión final&lt;/strong&gt;&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;Ya existe un Volumen I que muestra perfectamente cómo desarrollar en dos capas, usando las técnicas más que probadas que ofrece directamente Microsoft. Por lo tanto, la serie D se actualiza tal cual, mostrando técnicas propias de la programación multicapas. ¿Que es más complicado? Bueno... eso es valor añadido. Era una decisión sencilla, ¿verdad?&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-7284376213441832201?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/7284376213441832201/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=7284376213441832201&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7284376213441832201'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7284376213441832201'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/12/la-maldita-serie-d.html' title='La maldita serie D'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_QWaXq7W8dVI/R2VdIvrSXNI/AAAAAAAAAGQ/D01AG811vno/s72-c/owl.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-1478225045001372701</id><published>2007-12-13T16:20:00.000+01:00</published><updated>2008-12-11T09:01:33.646+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cursos'/><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='bases de datos'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>Next big thing</title><content type='html'>&lt;div align="justify" style="margin-bottom: 10px;"&gt;&lt;img style="float:right; margin:1px 0 1px 8px;border-style:none;padding:0px;" src="http://4.bp.blogspot.com/_QWaXq7W8dVI/R2FQJroeb-I/AAAAAAAAAGI/R-kU1nB3FsM/s320/mech.jpg" border="0" alt="" /&gt;&lt;span style="font-size:107%;font-variant:small-caps;"&gt;Próxima gran actualización del&lt;/span&gt; curso de ADO.NET: una serie dedicada a &lt;i&gt;LINQ for SQL&lt;/i&gt;. Voy a experimentar esta vez con un formato que creo que será mejor para esta materia: el curso estará basado en el vídeo (narrado y subtitulado).&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;El problema que veo con LINQ para SQL es que no es tan completo como la programación con &lt;i&gt;datasets&lt;/i&gt; para mover y actualizar datos entre capas. Por una parte, me he tropezado con la sorpresa de que los árboles de expresiones no vienen con soporte para la transmisión remota. Uno puede añadirlo por su cuenta, pero es bastante trabajo. Por lo tanto, cuando se piden datos a la capa intermedia, o regresas a la época en que pasabas una cadena, o te montas todo un tinglado para evaluar consultas remotas por tu cuenta y riesgo.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;El otro problema es más sutil: hasta que no te pones a hacer un ejemplo real no tropiezas con él. El caso es que las colecciones de LINQ for SQL (los tipos genéricos &lt;i&gt;Table&amp;lt;T&amp;gt;&lt;/i&gt; y &lt;i&gt;EntitySet&amp;lt;T&amp;gt;&lt;/i&gt;) no ofrecen algo parecido al &lt;i&gt;Merge&lt;/i&gt; de tablas y conjuntos de datos. Sí ofrecen la posibilidad de reasignar entidades al &lt;i&gt;data context&lt;/i&gt; local, y de serializar las colecciones de entidades, pero eso sólo simplifica las aplicaciones que no modifican datos en la capa de presentación: vale sólo para aplicaciones básicamente de sólo lectura. Nuevamente, uno puede programar lo que falta... pero ya son dos subsistemas bastante complejos que hay que añadir por cuenta y riesgo propio.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;Pero hay que contarlo todo, para verlo con perspectiva: a la actual versión de Visual Studio 2008 se le debe sumar, en relativamente poco tiempo, lo que en Microsoft llaman &lt;i&gt;ADO.NET Entity Framework&lt;/i&gt;, que es la verdadera continuación del viejo proyecto ObjectSpaces, que sufrió un cambio radical con la aparición de LINQ. Al parecer, este sistema será mucho más completo y ambicioso que el actual.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;A la espera del próximo gran invento, creo que lo mejor es ir explicando el trabajo con LINQ para SQL, que se parece bastante, sobre todo para evitar malas decisiones inducidas por las prisas. La actualización de las tres primeras series del curso deben ser también sencillas, porque son pocas las adiciones (la más notable, quizás, los nuevos coordinadores de grabación para relaciones que ahora se generan para los &lt;i&gt;table adapters&lt;/i&gt;).&lt;/div&gt;&lt;hr style="border-style:dotted; border-color: #C0C0E0; height:1px;"&gt;&lt;div align="justify" style="margin-bottom:10px;font-size:90%;font-style:italic;line-height: normal;"&gt;... de ahí la importancia del cambio de nombre de las series. La nueva serie sobre LINQ/SQL será la serie D, y la actual serie D se quedará en "volumen 2", como ya se refleja en los nuevos CDs del curso.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-1478225045001372701?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/1478225045001372701/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=1478225045001372701&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/1478225045001372701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/1478225045001372701'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/12/next-big-thing.html' title='Next big thing'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_QWaXq7W8dVI/R2FQJroeb-I/AAAAAAAAAGI/R-kU1nB3FsM/s72-c/mech.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-2721797564006683995</id><published>2007-12-07T15:19:00.000+01:00</published><updated>2008-12-11T09:01:33.981+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cursos'/><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>La espera</title><content type='html'>&lt;div style="text-align: right; font-style: italic; font-size: 90%; line-height: normal; margin-bottom: 10px;"&gt;The waiting is the hardest part&lt;br /&gt;Every day you see one more card&lt;br /&gt;You take it on faith, you take it to the heart&lt;br /&gt;The waiting is the hardest part&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;&lt;img style="float:left; margin:1px 12px 1px 0;border-style:none;padding:0px;" src="http://1.bp.blogspot.com/_QWaXq7W8dVI/R1lZVlNfGxI/AAAAAAAAAGA/2cR2ZtUi_Ak/s320/hourglass.jpg" border="0" alt="" /&gt;Ya está terminado el "Volumen I" del curso de ADO.NET, que incluye las series A, B y C completamente actualizadas. La serie B finalmente se ha quedado en unos pocos pero intensos ejercicios. Queda ahora "empaquetar" todo el contenido: vídeos, ejercicios y el manual del nuevo "volumen".&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;Y hay una estupenda noticia: a partir de la semana que viene, la oferta de libros "físicos" de nuestra tienda en Internet se amplia dramáticamente, con una nueva hornada de libros sobre ASP.NET, LINQ/C# 3.0 y WWF. Será una sorpresa agradable, se lo prometo :)&lt;/div&gt;&lt;hr&gt;&lt;ul type="square"&gt;&lt;li&gt;&lt;a href="http://www.marteens.com/pdfs/vol1-2.pdf"&gt;Temario combinado&lt;/a&gt; (PDF)&lt;/li&gt;&lt;/ul&gt;&lt;hr&gt;&lt;div style="text-align:justify;margin-bottom:10px;"&gt;Adelanto, sobre formas de actualizar o adquirir el curso de ADO.NET:&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Si adquirió el curso en agosto del 2007 o después: escríbame un email a la cuenta de IntSight, y recibirá el nuevo CD por correo certificado (paquete azul) &lt;b&gt;sin coste alguno&lt;/b&gt;.&lt;/li&gt;&lt;li&gt;Si adquirió el curso antes de esa fecha: &lt;b&gt;tampoco le costará&lt;/b&gt; nada. Pero la forma de actualización es mediante una descarga personalizada (ocupa unos 11MB). Escríbame para darle su dirección de descarga.&lt;/li&gt;&lt;li&gt;Alternativamente, si prefiere tener un CD "físico" con la actualización: voy a dar la posibilidad de recibir el &lt;b&gt;CD por un coste de 10 euros&lt;/b&gt; (dentro de España), y pago por tarjeta, transferencia o ingreso en cuenta (no reembolso).&lt;/li&gt;&lt;li&gt;Posibilidad interesante: vamos a vender, en nuestra tienda, nuevos libros sobre LINQ, ASP.NET y WWF. Si le interesa alguno de estos temas, compre cualquiera de estos libros, pague un euro más por el CD, y se ahorra los gastos de envío del CD (porque ya se incluyen en el coste del libro). Puedo tardar dos o tres días en crear los formularios de compra: si le urge, o quiere más información mientras tanto, &lt;b&gt;deme un toque por email&lt;/b&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-2721797564006683995?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/2721797564006683995/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=2721797564006683995&amp;isPopup=true' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2721797564006683995'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2721797564006683995'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/12/la-espera.html' title='La espera'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_QWaXq7W8dVI/R1lZVlNfGxI/AAAAAAAAAGA/2cR2ZtUi_Ak/s72-c/hourglass.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-7828474411238260306</id><published>2007-10-25T18:33:00.000+02:00</published><updated>2007-10-28T19:05:35.906+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='libros'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Métodos parciales y más</title><content type='html'>&lt;div style="margin-bottom: 10px;" align="justify"&gt;&lt;span style="font-size:108%;font-variant:small-caps;"&gt;Está disponible&lt;/span&gt; una actualización de &lt;a href="http://www.marteens.com/pdfs/csharp_intsight.pdf" target="_blank"&gt;Intuitive C#&lt;/a&gt; (28/octubre/2007). Esta versión añade secciones sobre &lt;em&gt;llamadas asíncronas&lt;/em&gt; a través de tipos delegados y el nuevo soporte para &lt;i&gt;métodos parciales&lt;/i&gt; y &lt;i&gt;propiedades automáticas&lt;/i&gt; en .NET 3.5/Visual Studio 2008. Hay también una pequeña sección sobre árboles de expresiones (¡son muy importantes para comprender cómo funcionan &lt;em&gt;LINQ for SQL&lt;/em&gt; y el futuro &lt;i&gt;LINQ for Entities&lt;/i&gt;!), como paso previo a LINQ. El libro ha pasado de 112 a 122 páginas.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-7828474411238260306?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/7828474411238260306/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=7828474411238260306&amp;isPopup=true' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7828474411238260306'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7828474411238260306'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/10/mtodos-parciales.html' title='Métodos parciales y más'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-1729593349730767623</id><published>2007-10-06T23:30:00.000+02:00</published><updated>2008-12-11T09:01:34.643+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cursos'/><category scheme='http://www.blogger.com/atom/ns#' term='ADO.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Quien avisa...</title><content type='html'>&lt;div&gt;&lt;b&gt;Actualización 9/oct&lt;/b&gt;: ¡Ya está terminada la actualización de la serie A! Ha costado por el nivel de profundidad del curso: tenga en cuenta que, a pesar de tratarse de una "serie A", se metía en temas como cifrado, compresión y las interfaces de muy bajo nivel del enlace de datos.&lt;/div&gt;&lt;div&gt;De todas maneras, antes de dar el pistoletazo oficial de salida, me queda fundir la serie C con la serie A (ya está adelantado más de la mitad del trabajo) y añadir algún ejercicio como puente entre ambas series, sobre todo sobre &lt;i&gt;DataReader's&lt;/i&gt; y comandos.&lt;/div&gt;&lt;div&gt;Lo bueno de la nueva serie A es que gran parte del material puede reciclarse para ser utilizado en la parte de enlace de datos de la próxima Cara Oculta de C# 3.0. En paralelo, estoy colaborando en un interesante proyecto de desarrollo en el que vamos a usar .NET Remoting. Como ve, las cosas se mueven en este mundo...&lt;/div&gt;&lt;hr&gt;&lt;div&gt;&lt;img style="float:right; margin:1px 0 1px 8px;" src="http://2.bp.blogspot.com/_QWaXq7W8dVI/RwgGWIqDjVI/AAAAAAAAAFQ/Mk7ru7B5POM/s320/abc.jpg" border="0" alt="" /&gt;&lt;span style="font-size: 108%; font-variant: small-caps;"&gt;Noticias sobre el&lt;/span&gt; curso de ADO.NET/C#:&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Estoy terminando la migración de la &lt;b&gt;serie A&lt;/b&gt; a &lt;b&gt;.NET v2.0&lt;/b&gt;.&lt;/li&gt;&lt;li&gt;También estoy &lt;b&gt;fundiendo&lt;/b&gt; la serie &lt;strong&gt;A&lt;/strong&gt; con la &lt;strong&gt;C&lt;/strong&gt; y con un par de ejercicios de lo que sería una miniserie &lt;strong&gt;B&lt;/strong&gt;.&lt;/li&gt;&lt;li&gt;De momento, la &lt;strong&gt;serie D&lt;/strong&gt; se queda tal cuál, pero las tres series del &lt;b&gt;volumen I&lt;/b&gt; son funcionalmente completas.&lt;/li&gt;&lt;li&gt;El &lt;b&gt;precio&lt;/b&gt; del curso &lt;b&gt;sube&lt;/b&gt;.&lt;/li&gt;&lt;li&gt;Pero quien compre ahora, o haya comprado en el mes de septiembre, no sólo compra al precio actual... sino que &lt;b&gt;recibe gratuitamente&lt;/b&gt; el CD con el &lt;b&gt;curso actualizado&lt;/b&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;div align="justify" style="margin-bottom:10px;"&gt;Quien avisa no es traidor...&lt;/div&gt;&lt;hr&gt;&lt;div&gt;Y esta es la imagen de portada del nuevo manual:&lt;/div&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;" src="http://4.bp.blogspot.com/_QWaXq7W8dVI/Rwk3hYqDjWI/AAAAAAAAAFY/KF9wGUMARnQ/s320/blob.jpg" border="0" alt="Programación con ADO.NET/C#" /&gt;&lt;div align="justify" style="margin-bottom:10px;"&gt;La elección no es gratuita: se trata de un objeto de tipo &lt;i&gt;blob&lt;/i&gt;, generado con &lt;a href="http://www.marteens.com/xsight/index.html"&gt;XSight RT&lt;/a&gt;. Los &lt;i&gt;blobs&lt;/i&gt; del &lt;a href="http://www.marteens.com/xsight/manual/rtdefined.html"&gt;&lt;i&gt;ray tracing&lt;/i&gt;&lt;/a&gt; se definen mediante &lt;a href="http://www.marteens.com/xsight/manual/shapes_blob.html"&gt;campos de fuerza puntuales&lt;/a&gt;: ahí donde la suma de las intensidades supera cierto umbral, existe el objeto. El resultado son estos objetos con formas casi "orgánicas", muy apropiados para modelar, por ejemplo, moléculas. El modelo de la imagen contiene dos blobs: el externo está formado por ocho puntos de fuerza, y el interno está formado por campos distorsionados, para producir elipses en lugar de esferas.&lt;/div&gt;&lt;div&gt;Para cada rayo de luz emitido, la aplicación debe resolver una ecuación de cuarto grado; algo parecido ocurre con las rosquillas, o &lt;a href="http://www.marteens.com/xsight/manual/shapes_torus.html"&gt;&lt;i&gt;toros&lt;/i&gt;&lt;/a&gt;. XSight RT implementa un algoritmo optimizado al detalle para resolver estas ecuaciones, y el resultado es que resulta más rápido generar una rosquilla en XSight RT que en algún &lt;i&gt;ray tracer&lt;/i&gt; implementado en C++ "nativo". Es todo un triunfo para C#, y uno de los motivos para elegir la imagen para la portada del manual.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-1729593349730767623?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/1729593349730767623/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=1729593349730767623&amp;isPopup=true' title='5 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/1729593349730767623'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/1729593349730767623'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/10/quien-avisa.html' title='Quien avisa...'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_QWaXq7W8dVI/RwgGWIqDjVI/AAAAAAAAAFQ/Mk7ru7B5POM/s72-c/abc.jpg' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-974131854701931671</id><published>2007-09-26T15:43:00.000+02:00</published><updated>2007-10-28T19:14:30.665+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='libros'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><title type='text'>Libros sobre ASP.NET</title><content type='html'>&lt;div&gt;&lt;iframe src="http://rcm.amazon.com/e/cm?t=callindrmarte-20&amp;o=1&amp;p=8&amp;l=as1&amp;asins=0735621764&amp;fc1=000000&amp;IS2=1&amp;lt1=_blank&amp;lc1=0000FF&amp;bc1=000000&amp;bg1=FFFFFF&amp;f=ifr&amp;nou=1" style="width:120px;height:240px;float:left;margin-right:8px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt;&lt;span class="first"&gt;Y ya puestos&lt;/span&gt; a recomendar libros, si necesita un buen libro para iniciarse con ASP.NET 2.0, mi libro recomendado es también de Dino Esposito: &lt;a href="http://www.amazon.com/dp/0735621764?tag=callindrmarte-20&amp;camp=14573&amp;creative=327641&amp;linkCode=as1&amp;creativeASIN=0735621764&amp;adid=0CZMFWBABV9M8GWAJ9ZY&amp;" target="_blank"&gt;Programming Microsoft ASP.NET 2.0, Core Reference&lt;/a&gt;.&lt;/div&gt;&lt;div style="margin-bottom: 10px;" align="justify"&gt;¿Hablamos un poco sobre &lt;a href="http://www.asp.net/" target="_blank"&gt;ASP.NET&lt;/a&gt;? Esta tecnología es la "culpable" de que abandonase el desarrollo de Sonata, los componentes con los que se desarrolló el viejo Classique. Sonata y ASP.NET compartían una misma idea: la de los controles declarativos en la plantilla HTML. La alternativa que ofrecía Delphi, y que me empujó en primer lugar a crear Sonata, era el componente tradicional de Delphi que, a lo largo de varias complicadas transformaciones, creaba la página final: usted no sólo tenía que programar la plantilla, sino también un "módulo Web" en el Delphi de toda la vida (estoy hablando de WebSnap). Sonata simplificaba todo eso, porque con un mínimo de programación en Delphi, mayormente relacionada con el modelo de datos, el escenario principal se trasladaba a la plantilla.&lt;/div&gt;&lt;div&gt;... y, para desgracia mía, ASP.NET 1.0 simplificaba muchísimo más las cosas. Naturalmente, hay mucho más en ASP.NET que el mero concepto de control declarativo, pero muchas de esas ideas ya estaban en los planes de desarrollo de Sonata. Con lo que no podía competir, sin embargo, era con el soporte en tiempo de diseño. Ni yo ni, por lo visto, la propia Borland (Delphi.NET incorpora las superficies de diseño para .NET de Microsoft).&lt;/div&gt;&lt;div&gt;ASP.NET 2.0 es una bestia impresionante, incluso comparándola con la versión anterior. Y lo digo en el mejor de los sentidos. Es muchísimo más eficiente que JSP (lo dicen las pruebas, no yo), y es infinitamente más elegante que el modelo propuesto por PHP. De hecho, he intercalado lo de "modelo" para dejar claro que ASP.NET &lt;i&gt;no es un lenguaje&lt;/i&gt;, sino una tecnología más amplia: usted puede elegir usarla con su lenguaje favorito para .NET, ya sea C&lt;sup&gt;#&lt;/sup&gt;, VB.NET o &lt;a href="http://www.chromesville.com" target="_blank"&gt;Chrome&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;Si tiene que aprender ASP.NET, ¿qué libros mejores que los de Dino Esposito? Oh, sí, quizás uno mío, pero aún no lo he escrito :)&lt;/div&gt;&lt;hr&gt;&lt;div&gt;Tres artículos que comparan C&lt;sup&gt;#&lt;/sup&gt; con Java:&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.marteens.com/trick53.htm" target="_blank"&gt;C# versus Java: eventos&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.marteens.com/trick5b.htm" target="_blank"&gt;C# versus Java: genericidad&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.marteens.com/trick5c.htm" target="_blank"&gt;C# versus Java: miscelánea&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-974131854701931671?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/974131854701931671/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=974131854701931671&amp;isPopup=true' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/974131854701931671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/974131854701931671'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/09/libros-sobre-aspnet.html' title='Libros sobre ASP.NET'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-7102093603438740413</id><published>2007-09-26T15:23:00.000+02:00</published><updated>2007-09-26T17:07:52.211+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='libros'/><category scheme='http://www.blogger.com/atom/ns#' term='AJAX'/><category scheme='http://www.blogger.com/atom/ns#' term='ASP.NET'/><title type='text'>Libros sobre AJAX</title><content type='html'>&lt;div align="justify" style="margin-bottom: 10px;"&gt;&lt;iframe src="http://rcm.amazon.com/e/cm?t=callindrmarte-20&amp;o=1&amp;p=8&amp;l=as1&amp;asins=0735624135&amp;fc1=000000&amp;IS2=1&amp;lt1=_blank&amp;lc1=0000FF&amp;bc1=000000&amp;bg1=FFFFFF&amp;f=ifr&amp;nou=1" style="width:120px;height:240px;float:left;margin-right:8px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt;&lt;span style="font-size:108%; font-variant:small-caps;"&gt;Si a estas&lt;/span&gt; alturas, todavía no ha oído hablar de AJAX... bueno, es que necesita un libro como éste. &lt;a href="http://www.amazon.com/dp/0735624135?tag=callindrmarte-20&amp;camp=14573&amp;creative=327641&amp;linkCode=as1&amp;creativeASIN=0735624135&amp;adid=1AEHRF5CBC5CYEEYNTMV&amp;" target="_blank"&gt;Introducing Microsoft ASP.NET AJAX&lt;/a&gt; es un libro más de &lt;b&gt;Dino Esposito&lt;/b&gt;, en mi opinión, el autor de los mejores libros sobre ASP.NET disponibles, y un colaborador habitual de la &lt;a href="http://msdn.microsoft.com/msdnmag/" target="_blank"&gt;MSDN Magazine&lt;/a&gt;.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;AJAX, por supuesto, significa &lt;i&gt;Asynchronous JavaScript And XML&lt;/i&gt; y, en pocas palabras, es una técnica que permite realizar peticiones concurrentes a un servidor HTML desde un browser, de manera que el resultado pueda utilizarse para actualizar la página a través de su árbol de objetos. ¿Demasiado larga la oración anterior? Bien: imagine que tiene una aplicación de bases de datos basada en HTML. Está mostrando un listado y quiere marcar y modificar un registro del listado. Con las técnicas "tradicionales", tendría que enviar un pedido al servidor y recuperar una nueva página completa. Con AJAX, podría enviar un pedido al servidor, igual que antes... pero recuperar solamente la parte de la página que ha sufrido cambios, y dejar que JavaScript combine la respuesta "parcial" con la página ya existente.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;En este momento, puede utilizar ASP.NET AJAX con Visual Studio 2005, por medio de unas extensiones de Microsoft. Y, por supuesto, Visual Studio 2008 ya vendrá con soporte para AJAX incorporado. Si quiere dedicarse en serio a la programación Web con ASP.NET, necesitará este libro. Eso sí: no es un libro para aprender ASP.NET, ni mucho menos.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-7102093603438740413?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/7102093603438740413/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=7102093603438740413&amp;isPopup=true' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7102093603438740413'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7102093603438740413'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/09/libros-sobre-ajax.html' title='Libros sobre AJAX'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-177289796791901021</id><published>2007-08-27T18:03:00.000+02:00</published><updated>2008-12-11T09:01:34.954+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cursos'/><category scheme='http://www.blogger.com/atom/ns#' term='COM+'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='remoting'/><title type='text'>Tras las vacaciones</title><content type='html'>&lt;div style="margin-bottom: 8px; text-align: right;"&gt;&lt;img style="float:left; margin:0 6px 0px 0px;border-style: none; padding: 0px;" src="http://4.bp.blogspot.com/_QWaXq7W8dVI/RtL6eKr_U-I/AAAAAAAAAFI/wJH6wLt7plk/s320/diploma.jpg" border="0" alt="" /&gt;&lt;span style="font-size: 108%; font-variant: small-caps;"&gt;Preparo un curso&lt;/span&gt; presencial para finales de septiembre, sobre .NET Remoting, servicios Webs y servicios corporativos (Enterprise Services = .NET sobre COM+).&lt;/div&gt;&lt;div style="margin-bottom: 8px; text-align: right;"&gt;Todavía tengo alguna duda sobre el formato (y por consiguiente, sobre fechas), pero lo más probable es que tenga formato de seminario de un día, en plan guerrilla (BYOL: &lt;i&gt;bring your own laptop&lt;/i&gt;, o &lt;i&gt;traiga su portátil&lt;/i&gt;) para abaratar precios. La documentación incluirá la "famosa" serie E, que estoy terminando ahora.&lt;/div&gt;&lt;div style="margin-bottom: 8px; text-align: right;"&gt;Coca Cola, cerveza y café, a cargo de IntSight...&lt;br /&gt;(&lt;i&gt;if you got the money, honey, we got your disease&lt;/i&gt;)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-177289796791901021?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/177289796791901021/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=177289796791901021&amp;isPopup=true' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/177289796791901021'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/177289796791901021'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/08/tras-las-vacaciones.html' title='Tras las vacaciones'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_QWaXq7W8dVI/RtL6eKr_U-I/AAAAAAAAAFI/wJH6wLt7plk/s72-c/diploma.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-5896525320178095992</id><published>2007-08-23T22:36:00.000+02:00</published><updated>2008-12-11T09:01:35.960+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Freya'/><category scheme='http://www.blogger.com/atom/ns#' term='sintaxis'/><category scheme='http://www.blogger.com/atom/ns#' term='ideas'/><category scheme='http://www.blogger.com/atom/ns#' term='LINQ'/><title type='text'>LINQ, Freya, Miranda</title><content type='html'>&lt;div align="justify" style="margin-bottom: 10px;"&gt;&lt;span style="font-size: 107%; font-variant: small-caps;"&gt;El siguiente listado&lt;/span&gt; muestra otra de las características "experimentales" de Freya: los &lt;i&gt;filtros de iteración&lt;/i&gt;.&lt;/div&gt;&lt;pre class="p"&gt;&lt;b&gt;for&lt;/b&gt; i &lt;b&gt;in&lt;/b&gt; 2..Max &lt;b&gt;div&lt;/b&gt; 2 : &lt;b&gt;not&lt;/b&gt; Result[i] &lt;b&gt;do&lt;br /&gt;begin&lt;/b&gt;&lt;br /&gt;    &lt;i&gt;// ... etcétera...&lt;/i&gt;&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;;&lt;/pre&gt;&lt;h3&gt;Freya&lt;/h3&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;img style="float:right; margin:2px 0 0px 8px;border-style:none;padding:0px;" src="http://1.bp.blogspot.com/_QWaXq7W8dVI/Rs7lHar_U7I/AAAAAAAAAEw/EdHxSlqKqnQ/s320/freya.jpg" border="0" alt="Freya" /&gt;Se trata de un pequeño fragmento del algoritmo de la &lt;a href="http://es.wikipedia.org/wiki/Criba_de_Erat%C3%B3stenes" target="_blank"&gt;Criba de Eratóstenes&lt;/a&gt;, implementado &lt;a href="http://www.marteens.com/freya/freya_ex11.html" target="_blank"&gt;en Freya&lt;/a&gt;, y muestra el uso de iteración mediante rangos y filtros. El bucle recorre valores enteros entre dos límites, pero sólo entrega aquellos números que no han sido marcados como primos todavía. El compilador traduce esta instrucción &lt;b&gt;for&lt;/b&gt; en un bucle &lt;b&gt;for&lt;/b&gt; numérico "clásico" con una instrucción &lt;b&gt;if&lt;/b&gt;/&lt;b&gt;then&lt;/b&gt; anidada. ¿Para qué tomarse entonces la molestia?&lt;/div&gt;&lt;ol start="1" style="margin-bottom: 4px;"&gt;&lt;li&gt;El minimalismo en lenguajes no es necesariamente bueno&lt;/li&gt;&lt;/ol&gt;&lt;div align="justify" style="margin-bottom: 8px; margin-left: 36px;"&gt;Esa es una curiosa superstición, que se desenmascara mirando lo que ocurre con Java. En este lenguaje, el repertorio de constructores de tipos es muy limitados: nada de delegados, nada de enumerativos, tipos de valor los justos... ¿Traspaso de parámetros por referencia? ¡Anatema, pecador! Copie el valor a modificar en la primera entrada de un &lt;i&gt;array&lt;/i&gt; de un solo elemento, y pase el &lt;i&gt;array&lt;/i&gt; como parámetro. ¿Necesito seguir?&lt;/div&gt;&lt;ol start="2" style="margin-bottom: 4px;"&gt;&lt;li&gt;La combinación de rango más filtro aumenta mucho la expresividad&lt;/li&gt;&lt;/ol&gt;&lt;div align="justify" style="margin-bottom: 8px; margin-left: 36px;"&gt;Mi teoría es que, en este caso, una simple ojeada a la cabecera del bucle deja las intenciones muy claras. Si no me cree, piense que ha escrito un &lt;b&gt;for&lt;/b&gt; con un &lt;b&gt;if&lt;/b&gt; anidado, y que la instrucción condicional tiene un bloque de instrucciones relativamente largo. ¿Cuánto tiempo tardaría en averiguar si existe una cláusula &lt;b&gt;else&lt;/b&gt; o si se trata de un simple &lt;b&gt;if&lt;/b&gt;/&lt;b&gt;then&lt;/b&gt;? Espero que coincida conmigo en que se trata de dos patrones algorítmicos muy diferentes.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Confieso, no obstante, que llegue a lo creo un buen diseño gracias a una confusión. Freya se está diseñando, desde el primer momento, mediante un método que podríamos llamar &lt;i&gt;mutación, erosión y selección&lt;/i&gt;, siguiendo un patrón similar al que ocurre con los lenguajes humanos. La mutación puede ocurrir deliberadamente o por error. Por ejemplo, en los primeros días, cuando Freya se parecía muchísimo más a Delphi, escribí por error una declaración de variable "global" dentro de una sección de implementación. Pero me di cuenta enseguida de que podía reinterpretar la declaración como una variable &lt;i&gt;de instancia&lt;/i&gt; privada. Este un ejemplo de &lt;i&gt;mutación&lt;/i&gt;. Un buen ejemplo de &lt;i&gt;erosión&lt;/i&gt; es la omisión del nombre de la clase en el &lt;b&gt;constructor&lt;/b&gt;. Al principio, el constructor llevaba el mismo nombre de la clase, pero un buen día olvidé escribir el nombre... y me di cuenta que era innecesario. Naturalmente, la &lt;i&gt;selección&lt;/i&gt; es el proceso posterior a estos errores: es cuando me digo &lt;i&gt;"y vio Ian que era bueno"&lt;/i&gt;.&lt;/div&gt;&lt;h3&gt;Miranda&lt;/h3&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;img style="float:right; margin:0 0 0px 8px; border-style: none; padding: 0px;" src="http://1.bp.blogspot.com/_QWaXq7W8dVI/Rs7kGar_U6I/AAAAAAAAAEo/24hKZuiFauE/s320/miranda.jpg" border="0" alt="Miranda" /&gt;¿Cuál fue mi error inicial, en este caso? Freya ya tenía rangos, que permitían tres usos: el uso trivial en instrucciones &lt;b&gt;case&lt;/b&gt;, como operandos en el lado derecho del operador &lt;b&gt;in&lt;/b&gt; y como iteradores en la instrucción &lt;b&gt;for&lt;/b&gt;... sin filtros en aquel momento. Cuando me di cuenta de la frecuencia de aparición de iteración más selección en los ejemplos, pensé en introducir algo parecido a las &lt;i&gt;expresiones de Zermelo-Frankel&lt;/i&gt;. Este ejemplo pertenece a &lt;a href="http://miranda.org.uk/" target="_blank"&gt;Miranda&lt;/a&gt;:&lt;/div&gt;&lt;pre style="margin-left: 32px; margin-bottom: 8px; line-height: 110%;"&gt;[ n | n &lt;- [1..5] ; n mod 2 = 0 ]&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Una expresión ZF, o &lt;i&gt;list comprehension&lt;/i&gt;, en la jerga funcional, permite directamente las tres operaciones más importantes soportadas por LINQ: iteración, selección y proyección. ¿Por qué no sustituir ese desagradable dialecto llamado SQL (¡sí, SQL como lenguaje es malísimo!) por un formalismo más elegante? Tenga presente que en mi ejemplo, el filtro se ha aplicado a un rango, pero en realidad, Freya permite usarlo con &lt;i&gt;cualquier iterador&lt;/i&gt;...&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;En realidad, se trata de dos errores. El primero, es que la combinación de iterador más filtro no es, hablando con propiedad, una expresión de Zermelo-Frankel &lt;i&gt;completa&lt;/i&gt;, pues necesita la variable de iteración para tener sentido. La primera consecuencia es que la idea no puede trasladarse automáticamente al operador &lt;b&gt;in&lt;/b&gt;. Para verlo, sólo intente escribir una expresión &lt;b&gt;in&lt;/b&gt; sobre un iterador filtrado. Es cierto que estas expresiones de pertenencia no ganan mucho cuando el iterador es un rango numérico, pero tenga presente que Freya permite usar el operador &lt;b&gt;in&lt;/b&gt; con cualquier tipo que publique un método &lt;i&gt;Contains&lt;/i&gt; (sí, hay que ampliarlo todavía para que maneje el tipo &lt;i&gt;IEnumerable&lt;/i&gt; a secas).&lt;/div&gt;&lt;h3&gt;LINQ&lt;/h3&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;img style="float:right; margin:2px 0 0px 8px;border-style:none;padding:0px;" src="http://2.bp.blogspot.com/_QWaXq7W8dVI/Rs7mCqr_U8I/AAAAAAAAAE4/stf6vw6Hwr0/s320/linq.jpg" border="0" alt="The Missing LINQ" /&gt;No se trata, sin embargo, de un error grave: a pesar de no poder aplicarse directamente a las pruebas de pertenencia, el recurso sigue siendo útil para los bucles &lt;b&gt;for&lt;/b&gt;, como ya he explicado, por lo que mantuve la idea. El segundo error es más interesante: ¿pueden realmente las expresiones ZF reemplazar a LINQ? Con las debidas extensiones... sí. Pero estamos perdiendo de vista algo muy importante. Mi idea, realmente, era poder compilar &lt;b&gt;eficientemente&lt;/b&gt; las expresiones de este tipo. Ahora mismo, C# 3.0 permite escribir código como el siguiente:&lt;/div&gt;&lt;pre style="margin-left: 32px; margin-bottom: 8px; line-height: 110%;"&gt;List&amp;lt;&lt;b&gt;int&lt;/b&gt;&amp;gt; lista = { 1, 2, 3, 4, 5 };&lt;br /&gt;&lt;b&gt;if&lt;/b&gt; (lista.Exists(x =&amp;gt; x % 2 == 0))&lt;br /&gt;{&lt;br /&gt;    &lt;i&gt;// ... etcétera...&lt;/i&gt;&lt;br /&gt;}&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;No se trata de LINQ directamente, por cuestiones sintácticas, pero sí es la base de la implementación de LINQ: la prueba de existencia se convierte en una llamada a un método que recibe un delegado (un puntero a método, al fin y al cabo). ¿Eficiencia de la llamada? Asquerosa. Sí, es muy expresivo, pero sería mucho más rentable expandir el bucle de búsqueda en línea... si éste no consumiese tanto espacio y no ocultase nuestras intenciones.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Imagine ahora lo que ocurrirá cuando LINQ esté disponible: en principio, le permitirá acrobacias más complicadas con la nueva sintaxis... al precio de convertir su aplicación en una lenta babosa caracolera. ¿Significa esto que LINQ es un error? ¡De ningún modo! Pero el motivo por el que LINQ tiene sentido no está siendo debidamente explicado por los evangelistas entusiastas de la idea que pululan por foros y bitácoras. Y no me di cuenta del problema hasta haber experimentado con la característica de Freya que acabo de explicar.&lt;/div&gt;&lt;h3&gt;Code is data&lt;/h3&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;img style="float:right; margin:0 0 0px 8px; border-style: none; padding: 0;" src="http://2.bp.blogspot.com/_QWaXq7W8dVI/Rs7ivqr_U5I/AAAAAAAAAEg/7tEAyoO3UgI/s320/ouro.jpg" border="0" alt="Ouroboros" /&gt;El verdadero corazón y sentido de LINQ no son esas amaneradas imitaciones de la sintaxis de SQL... sino los &lt;b&gt;árboles de expresiones&lt;/b&gt;. Seamos sinceros: si LINQ sólo se pudiese usar con estructuras en memoria como las listas, sería una porquería del tamaño de la suma de todos los libros impresos sobre Java. Sería una porquería porque no habríamos logrado nada compilando estas construcciones como llamadas a métodos de la biblioteca de clases. Excepto ineficiencia, claro...&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;¿Por qué hay que llamar, entonces, a métodos de la biblioteca de clases? Pues porque, en &lt;i&gt;algunos casos&lt;/i&gt;, como deja entrever la publicidad sobre LINQ, estos métodos, en vez de recibir delegados asociados a métodos anónimos, exigirán que el compilador les pase esos misteriosos &lt;i&gt;árboles de expresiones&lt;/i&gt;. ¿A qué tipo de datos pertenece el parámetro del método en la siguiente llamada?&lt;/div&gt;&lt;pre style="margin-left: 32px; margin-bottom: 8px; line-height: 110%;"&gt;sequence.Where(x =&amp;gt; x % 2 == 0)&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;En la mayoría de los casos, se tratará de un tipo delegado, pero podría tratarse de un árbol de expresiones. En ese segundo caso, sería el propio compilador de C# (como muestra la beta de Orcas) quien debería crear una estructura en memoria que reflejase la estructura de la expresión lambda para pasarla como parámetro. Es un comportamiento importantísimo, pero muy poco documentado.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;¿Para qué puede querer un método recibir un árbol de expresiones, en vez de un puntero a método? Motivos sobran. Por ejemplo, el método puede transformar el árbol en una cadena que represente una instrucción SQL para pasarla a un servidor SQL. O el método puede formar parte de la capa de comunicación con un servidor remoto, y enviar una versión serializada del árbol para que sea evaluado al otro lado de la red. Estos son los casos &lt;i&gt;reales&lt;/i&gt; de uso de LINQ, no esas tonterías de manipulación de listas en memoria que muestran casi todos los ejemplos.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;¿Se da cuenta que LINQ, hasta cierto punto, nos retrotrae a los tiempos en que estaba de moda considerar el código como datos? De hecho, ¡podemos convertir fácilmente un árbol de expresiones en código nativo ejecutable! Si usted guarda fórmulas para los gastos de envío en una base de datos, seguirá necesitando un pequeño analizador sintáctico para convertirlas en árboles de expresiones. Pero ya podrá delegar en el sistema la conversión del árbol en código. ¿No es estupendo?&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Resumiendo: LINQ es una buena idea, pero está siendo mal explicada. El riesgo que se corre es que aparezcan aplicaciones que utilicen LINQ de forma incorrecta... como, efectivamente, sugieren la mayoría de los ejemplos disponibles, incluso de la propia Microsoft. En segundo lugar, una vez que se comprende este problema, se comprende también que existe una puerta abierta en el diseño de lenguajes para .NET. Puede que sea beneficioso aumentar la potencia expresiva de las operaciones sobre listas mediante una sintaxis especial, paralela a la de LINQ. O puede que lo indicado sea la optimización de las llamadas a determinados métodos de determinadas clases, ya sea por medio del compilador o por medio de alguna utilidad aplicada al ensamblado compilado... pues dudo que el JIT llegue a estos extremos.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-5896525320178095992?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/5896525320178095992/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=5896525320178095992&amp;isPopup=true' title='10 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/5896525320178095992'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/5896525320178095992'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/08/linq-freya-miranda.html' title='LINQ, Freya, Miranda'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_QWaXq7W8dVI/Rs7lHar_U7I/AAAAAAAAAEw/EdHxSlqKqnQ/s72-c/freya.jpg' height='72' width='72'/><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-5381497360906389777</id><published>2007-08-20T20:29:00.000+02:00</published><updated>2008-12-11T09:01:36.198+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Freya'/><category scheme='http://www.blogger.com/atom/ns#' term='sintaxis'/><title type='text'>Liaison</title><content type='html'>&lt;div align="justify" style="margin-bottom: 10px;"&gt;&lt;span style="font-size: 107%; font-variant: small-caps;"&gt;¿Es Pascal un&lt;/span&gt; lenguaje "verboso"? Depende de con cuál lenguaje lo comparemos, por supuesto, pero en términos generales, se puede decir que sí lo es, porque introduce mucha redundancia en determinadas construcciones sintácticas.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Eche un vistazo a la siguiente, por poner un simple ejemplo:&lt;/div&gt;&lt;pre style="margin-left: 32px; margin-bottom: 8px; line-height: 110%;"&gt;&lt;b&gt;for&lt;/b&gt; i := 0 &lt;b&gt;to&lt;/b&gt; 9 &lt;b&gt;do&lt;br /&gt;begin&lt;/b&gt;&lt;br /&gt;    WriteLn(i);&lt;br /&gt;    WriteLn(i * i);&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;;&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;Parece un código tan claro que casi brilla, pero ¿adivina qué es lo que sobra? Le daré una pista: localice dos palabras reservadas consecutivas...&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Y esto, ¿qué le parece?:&lt;/div&gt;&lt;pre style="margin-left: 32px; margin-bottom: 8px; line-height: 110%;"&gt;&lt;b&gt;for&lt;/b&gt; i := 0 &lt;b&gt;to&lt;/b&gt; 9&lt;br /&gt;&lt;b&gt;begin&lt;/b&gt;&lt;br /&gt;    WriteLn(i);&lt;br /&gt;    WriteLn(i * i);&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;;&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;&lt;img style="float:right; margin:1px 0 0 8px; padding:0; border-style:none;" src="http://4.bp.blogspot.com/_QWaXq7W8dVI/Rsnisar_U2I/AAAAAAAAAEI/0vamCqnkOZs/s320/ae.jpg" border="0" alt="" /&gt;Efectivamente, he eliminado la palabra clave &lt;b&gt;do&lt;/b&gt; por estar ubicada antes de un &lt;b&gt;begin&lt;/b&gt;. En general, la penúltima sintaxis de Freya permite, como opción, eliminar los &lt;b&gt;do&lt;/b&gt; y los &lt;b&gt;then&lt;/b&gt; que van antes de instrucciones que empiecen con palabras reservadas. Esta medida es parte de un esfuerzo de limpieza de la sintaxis que se ha cargado también construcciones propias de Freya como &lt;a href="http://www.marteens.com/freya/freya_ex11.html" target="_blank" title="Criba de Eratóstenes"&gt;&lt;b&gt;for var&lt;/b&gt;&lt;/a&gt;, que antes indicaba que estaba teniendo lugar una inferencia de tipo para una variable local.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;Una aclaración: dos palabras claves consecutivas no siempre indican redundancia. Sólo es así cuando la palabra clave sólo hace de "esqueleto", es decir, cuando su papel es evitar ambigüedades sintácticas.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;¡Ah!, y si se pregunta por qué me preocupan ahora los lenguajes verbosos y la redundancia innecesaria: estoy harto de pagar precios astronómicos por la puñetera tinta de impresora, el tóner y el papel. Hay más razones, pero ésta es importante y me parece incluso suficiente...&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-5381497360906389777?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/5381497360906389777/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=5381497360906389777&amp;isPopup=true' title='17 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/5381497360906389777'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/5381497360906389777'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/08/liaison.html' title='Liaison'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_QWaXq7W8dVI/Rsnisar_U2I/AAAAAAAAAEI/0vamCqnkOZs/s72-c/ae.jpg' height='72' width='72'/><thr:total>17</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-7934324643628235676</id><published>2007-08-18T18:16:00.000+02:00</published><updated>2007-08-18T18:17:09.855+02:00</updated><title type='text'>Perú</title><content type='html'>Llegan malas noticias desde Perú. Si conocéis alguna forma de ayudar...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-7934324643628235676?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/7934324643628235676/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=7934324643628235676&amp;isPopup=true' title='1 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7934324643628235676'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7934324643628235676'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/08/per.html' title='Perú'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-3054391830334382900</id><published>2007-08-15T22:34:00.000+02:00</published><updated>2008-12-11T09:01:36.355+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='yo'/><category scheme='http://www.blogger.com/atom/ns#' term='ideas'/><title type='text'>Enigma</title><content type='html'>&lt;div align="justify" style="margin-bottom: 10px;"&gt;&lt;img style="float:right; margin:1px 0 1px 8px;" src="http://1.bp.blogspot.com/_QWaXq7W8dVI/RsNmZxKMnAI/AAAAAAAAAEA/_Yed0jEnDIM/s320/clouds.jpg" border="0" alt="" /&gt;&lt;span style="font-size: 107%; font-variant: small-caps;"&gt;¿Qué son los números&lt;/span&gt; complejos? Rostros que imaginamos en la Máquina de Turing.&lt;/div&gt;&lt;hr&gt;&lt;div align="justify" style="font-size: 90%; font-style: italic; margin: 1px 0px 10px 24px;"&gt;La frase parece un sinsentido, pero tiene que ver con la forma que esperamos que adopten las teorías físicas más básicas. ¿Se ha preguntado alguna vez si el Universo es &lt;b&gt;computable&lt;/b&gt;? Hay físicos que ya se lo están preguntando, aunque no hay aún una respuesta definitiva, sino una esperanza: que, efectivamente, lo sea. Y si lo es, la Ultima Realidad Física podría ser un mero proceso informático, aunque de una potencia brutal. Todo algoritmo sería, en realidad, un subalgoritmo dentro de un algoritmo global (¿conoce el sentido en Física de la frase "la vista de Dios"?). Y las entidades "platónicas" como los números complejos, que tanto han atormentado a Roger Penrose, serían el resultado de intentar analizar el funcionamiento de la Máquina mediante técnicas "orientadas a objetos". Algo parecido a los rostros que el ojo humano termina por ver en cualquier nube de verano.&lt;/div&gt;&lt;div align="justify" style="font-size: 90%; font-style: italic; margin: 1px 0px 10px 24px;"&gt;... y no, no he bebido ni fumado nada raro :)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-3054391830334382900?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/3054391830334382900/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=3054391830334382900&amp;isPopup=true' title='6 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/3054391830334382900'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/3054391830334382900'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/08/enigma.html' title='Enigma'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_QWaXq7W8dVI/RsNmZxKMnAI/AAAAAAAAAEA/_Yed0jEnDIM/s72-c/clouds.jpg' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-2020169533439729006</id><published>2007-08-15T22:07:00.001+02:00</published><updated>2007-08-15T22:08:46.288+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='libros'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Para febrero del 2008...</title><content type='html'>&lt;img style="display:block; margin:0px auto 10px; text-align:center;" src="http://www.marteens.com/images/dscs3.jpg" border="0" alt="" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-2020169533439729006?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/2020169533439729006/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=2020169533439729006&amp;isPopup=true' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2020169533439729006'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2020169533439729006'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/08/para-febrero-del-2008.html' title='Para febrero del 2008...'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-740063838418440280</id><published>2007-08-09T01:04:00.000+02:00</published><updated>2007-08-09T01:07:36.468+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='libros'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Nueva versión de Intuitive C#</title><content type='html'>Hay nueva versión de &lt;a href="http://www.marteens.com/pdfs/csharp_intsight.pdf" target="_blank"&gt;Intuitive C#&lt;/a&gt;. Sigue siendo un libro incompleto, aunque hay 30 páginas más que en la última versión. No he intentado disimular los huecos (sobre todo en el capítulo 2). No sé si voy a tener tiempo para seguir actualizando este libro: más prioridad tienen el nuevo libro (para febrero de 2008) y el curso de ADO.NET (para septiembre).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-740063838418440280?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/740063838418440280/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=740063838418440280&amp;isPopup=true' title='5 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/740063838418440280'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/740063838418440280'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/08/nueva-versin-de-intuitive-c.html' title='Nueva versión de Intuitive C#'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-6231756646223270472</id><published>2007-07-02T11:41:00.000+02:00</published><updated>2007-07-03T09:54:01.041+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Freya'/><title type='text'>El fichero de ayuda de Freya</title><content type='html'>Está en inglés y no está terminada, pero es la documentación más exacta respecto al estado actual de Freya:&lt;br /&gt;&lt;br /&gt;&lt;ul type="square"&gt;&lt;li&gt;&lt;a href="http://www.marteens.com/freya/help" target="_blank"&gt;Ayuda HTML de Freya&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;Ayer intenté subir el fichero compilador CHM, pero al descargarlo para probar, me daba problemas con las zonas de seguridad. La solución más rápida era generar un instalador, pero me pareció excesiva.&lt;hr&gt;Lo decía en un comentario, pero lo repito aquí arriba: preparaos para un &lt;b&gt;megalibro sobre C# a finales de año&lt;/b&gt;. Como suele ocurrir en estas cosas, va a ser el mejor libro que he escrito hasta el momento: por temática, por tratamiento, por concisión y por estilo. Sobre esto último, una de las "novedades" que he mantenido ocultas en este período es que finalmente he puesto una lanza en la escritura "de ficción"... usando un pseudónimo. No creo que me vaya a "forrar" de momento, ni a producir mucho revuelo literario... de momento, pero las consecuencias para mi trabajo de informático es que ahora escribo un poco mejor, incluyendo los libros técnicos.&lt;br /&gt;&lt;br /&gt;... y no, no voy a mezclar lo que debe ir separado.&lt;hr&gt;Y no os preocupéis, amigos, que no se trata de una depresión. La depresión es una enfermedad seria, que afecta por igual a hombres y mujeres, pero mis cabreos no van por ahí. De hecho, quienes me conocen personalmente saben que lo más frecuente es encontrarme cabreado, o por darle algo de dignidad, "justamente indignado". Se podría escribir un libro que comenzase &lt;i&gt;Canta, oh diosa, la cólera del martínida Ian...&lt;/i&gt;.&lt;hr&gt;Para que no os aburráis demasiado, los que aún no estáis de vacaciones, ahí va una de las ventajas de Freya (Enrique, te debo un mensaje... y a Jaime, y a Nico, y a David...) respecto a alternativas similares: &lt;b&gt;las interfaces en Freya pueden incluir aserciones&lt;/b&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre style="margin-left: 32px; margin-bottom: 2px; line-height: 110%;"&gt;IStack = &lt;b&gt;interface&lt;/b&gt;[X]&lt;br /&gt;    &lt;b&gt;property&lt;/b&gt; IsEmpty: Boolean; &lt;b&gt;readonly&lt;/b&gt;;&lt;br /&gt;    &lt;b&gt;property&lt;/b&gt; Top: X; &lt;b&gt;readonly&lt;/b&gt;;&lt;br /&gt;        &lt;b&gt;requires not&lt;/b&gt; IsEmpty;&lt;br /&gt;&lt;br /&gt;    &lt;b&gt;method&lt;/b&gt; Push(Value: X);&lt;br /&gt;        &lt;b&gt;ensures&lt;/b&gt; Top.Equals(Value);&lt;br /&gt;    &lt;b&gt;method&lt;/b&gt; Pop: X;&lt;br /&gt;        &lt;b&gt;requires not&lt;/b&gt; IsEmpty;&lt;br /&gt;        &lt;b&gt;ensures&lt;/b&gt; Result.Equals(&lt;b&gt;old&lt;/b&gt; Top);&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;;&lt;/pre&gt;&lt;br /&gt;De hecho, ¡no tendría mucho sentido tener un lenguaje con interfaces y aserciones, y que estos dos recursos no se pudieran combinar! Se trata, además, de una combinación segura, no problemática: más problemas, tanto teóricos como prácticos, da la transmisión de aserciones a través de una cadena de herencia.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-6231756646223270472?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/6231756646223270472/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=6231756646223270472&amp;isPopup=true' title='5 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/6231756646223270472'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/6231756646223270472'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/07/el-fichero-de-ayuda-de-freya.html' title='El fichero de ayuda de Freya'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-7607633357942042656</id><published>2007-06-24T22:46:00.001+02:00</published><updated>2007-06-25T02:14:43.488+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Freya'/><category scheme='http://www.blogger.com/atom/ns#' term='ideas'/><title type='text'>Un patrocinador para Freya</title><content type='html'>Si trabajas en una empresa lo suficientemente grande como para que pueda asumir el reto, quizás a tu jefe... o a tí, si eres el jefe, le pueda interesar patrocinar el proyecto Freya.&lt;br /&gt;&lt;br /&gt;&lt;div align="center"&gt;&lt;img src="http://www.marteens.com/freya/images/freya.jpg" align="center" /&gt;&lt;/div&gt;&lt;br /&gt;¿Qué motivos puede haber para patrocinar un proyecto de este tipo?&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Históricamente, muchos de los lenguajes de programación de los que ahora disponemos han surgido del mecenazgo de importantes empresas tecnológicas, que no eran exactamente consultorías especializadas en Informática. Los casos más conocidos son los de AT&amp;T, de donde salieron C y C++, y el del Departamento de Defensa de los Estados Unidos, que fue la cuna de Ada.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Ayuntamientos de grandes ciudades, o comunidades autónomas, pueden encontrar interesante el proyecto. Por una parte, muchas veces funcionan como grandes empresas, y se suponen que apoyan la iniciativa empresarial, la creación de puestos de trabajos, etc, etc. Conozco, por ejemplo, un proyecto de entorno de desarrollo y compilador para COBOL, patrocinado en su momento por la Comunidad Valenciana, y los ejemplos de patrocinio de distros de Linux son muchos.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Para una empresa, puede ser interesante el patrocinio gracias a las ventajas fiscales de este tipo de ayudas.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Y están las ventajas obvias: publicidad, tanto en Internet como en libros y cursos, material de formación gratuito para la empresa, etc, etc.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;... y observe que no entro, deliberadamente, en las ventajas técnicas: una empresa con un potente departamento de software puede beneficiarse enormemente por disponer de una tecnología como la de Freya. Incluso no se trata ya del propio lenguaje: está la experiencia en el propio entorno, la posibilidad de crear lenguajes especiales dependientes del dominio, el desarrollo de herramientas para lenguajes existentes, como verificadores estáticos, analizadores de flujo, etc. Incluso empresas que comercializan un producto de software pueden utilizar este &lt;i&gt;know how&lt;/i&gt; para incorporar lenguajes de script en su producto principal.&lt;/li&gt;&lt;/ol&gt;Claro, todo depende de cuánto sea necesario gastar en el patrocinio. Pues bien, las cuentas pueden salirle incluso en este sentido. Objetivamente, el gasto mínimo consistiría en un apoyo salarial para un programador durante un plazo de un año (luego hablaré de plazos y objetivos). Al no ser necesaria una dedicación al 100%, ni siquiera se trata de un salario completo (con los extras de retenciones fiscales, seguridades sociales, etc, etc). No voy a hablar de cifras en público, pero tenga presente que estoy hablando de una fracción de un salario.&lt;br /&gt;&lt;br /&gt;¿El estado del proyecto? El compilador está prácticamente terminado. Durante el año del patrocinio, el objetivo sería redondear un entorno de desarrollo propio (completando &lt;a href="http://commanet.blogspot.com/2007/04/espada-afilada.html"&gt;SharpBlade&lt;/a&gt;) o adaptar el compilador para su uso dentro de Visual Studio o SharpDevelop. Ya hay bastante trabajo hecho en esta dirección, por supuesto.&lt;br /&gt;&lt;br /&gt;Por último, hay otra opción posible: si le interesa adquirir derechos sobre Freya, incluso sobre el producto completo. No es la opción que veo más probable, pero es posible, y sería cuestión de negociarlo.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-7607633357942042656?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/7607633357942042656/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=7607633357942042656&amp;isPopup=true' title='5 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7607633357942042656'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7607633357942042656'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/06/un-patrocinador-para-freya.html' title='Un patrocinador para Freya'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-2181403867789408898</id><published>2007-06-24T06:04:00.000+02:00</published><updated>2007-06-24T20:15:07.519+02:00</updated><title type='text'>Busco trabajo</title><content type='html'>Busco trabajo como programador, analista o jefe de proyecto. 18 años de experiencia laboral demostrables. Pueden ser proyectos como freelance o a tiempo completo o parcial. Motivo: hartazgo de funcionar como empresario y que Hacienda se lleve casi todo lo que gano.&lt;br /&gt;&lt;br /&gt;Mi nombre es Ian. Mi actual empresa es IntSight. Mi dirección de correos es mi_nombre arroba mi_empresa puntocom.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-2181403867789408898?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/2181403867789408898/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=2181403867789408898&amp;isPopup=true' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2181403867789408898'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2181403867789408898'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/06/busco-trabajo.html' title='Busco trabajo'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-7014853435648106696</id><published>2007-06-15T13:45:00.000+02:00</published><updated>2007-08-15T22:48:00.742+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ideas'/><title type='text'>Lo pequeño y lo grande</title><content type='html'>&lt;div align="justify" style="margin-bottom: 10px;"&gt;&lt;a href="http://www.microsoft.com/surface" target="_blank"&gt;&lt;img src="http://www.marteens.com/images/msurf.png" border="0" style="float: right; margin: 1px 0 1px 8px;"/&gt;&lt;/a&gt;&lt;span style="font-size: 108%; font-variant: small-caps;"&gt;¿Ha visto ya&lt;/span&gt; las noticias sobre &lt;a href="http://www.microsoft.com/surface" target="_blank"&gt;Microsoft Surface&lt;/a&gt;? Por si le da pereza seguir el enlace, o si no tiene ahora mismo una conexión decente a Internet, le resumo la idea: se trata de un ordenador sin teclado ni ratón. Tiene pequeñas cámaras bajo el cristal de protección que siguen los movimientos de los objetos que entran en contacto con el cristal. De esa manera distinguen los dedos de otros dispositivos con los que pueden interactuar.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;Aunque no parezca complicado a simple vista, algo tan sencillo abre muchas puertas... e introduce algún que otro problema. En un ordenador convencional, hay un único cursor para el ratón. En la superficie, por el contrario, se pueden usar simultáneamente varios dedos. Es posible que dos o más personas utilicen simultáneamente la superficie, mientras que nuestros ordenadores asumen por lo general que los está manejando un único usuario.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;Mientras veía el vídeo pensé en cómo estaría implementado el software del sistema. Naturalmente, bajo la superficie (nunca mejor dicho) hay un Windows Vista, pero me refiero al lenguaje en que se programan las aplicaciones especializadas para esta plataforma. Y me he dado cuenta de otra ventaja con .NET que los antiguos programadores de Delphi no teníamos:&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;Suponga que retrocedemos a la época anterior a .NET. ¿Cómo accederíamos a las nuevas APIs desde Delphi "clásico"? Lo más probable es que la nueva API residiese en una DLL. Por lo tanto, los programadores Delphi tendrían que esperar a una traducción de las cabeceras de C++ a Pascal para poder hincarle el diente. ¿Cuánto tiempo se tardaba, típicamente, en aquellos gloriosos años? Tenga en cuenta, además, que muchas veces estas interfaces traducidas contenían errores de traducción: ocurrió en su momento con el software de la mismísima Borland.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;En claro contraste, esta traducción no es necesaria en .NET. Da igual el lenguaje con el que haya sido programado el API de la superficie: cualquier lenguaje .NET (¡sí, incluyendo Freya!) puede empezar a trabajar con el API, pues la traducción es automática, sin necesidad de intermediarios.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;¿Una insignificancia? Puede. Pero sin importar lo pequeña que sea, se trata de una ventaja, o más bien, de una de las muchas pequeñas ventajas de la migración a .NET. A veces la cercanía a los árboles nos impide disfrutar del bosque.&lt;/div&gt;&lt;hr&gt;&lt;div align="justify" style="font-size: 90%; font-style: italic; margin: 1px 24px 10px 24px;"&gt;De momento, se trata de un dispositivo caro. Al parecer, Microsoft empezará implantándolo en hoteles y bares de "alto standing". He visto también una aplicación de un dispositivo parecido, si no es el mismo, para implementar un sintetizador, en una universidad española. El punto fuerte del sintetizador era que permitía que varias personas lo "tocasen": no usaba teclas, sino que "respondía" al contacto con los dedos y con figuras geométricas predefinidas, a modo de fichas.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-7014853435648106696?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/7014853435648106696/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=7014853435648106696&amp;isPopup=true' title='7 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7014853435648106696'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7014853435648106696'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/06/lo-pequeo-y-lo-grande.html' title='Lo pequeño y lo grande'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-3305927071090840943</id><published>2007-06-13T02:29:00.000+02:00</published><updated>2007-06-13T02:33:07.398+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='yo'/><title type='text'>It's just a spring clean for the May Queen</title><content type='html'>&lt;i&gt;There's a feeling I get&lt;br /&gt;when I look to the West, &lt;br /&gt;and my spirit is crying for leaving...&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-3305927071090840943?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/3305927071090840943/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=3305927071090840943&amp;isPopup=true' title='12 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/3305927071090840943'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/3305927071090840943'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/06/its-just-spring-clean-for-may-queen.html' title='It&apos;s just a spring clean for the May Queen'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-2063772769507982818</id><published>2007-06-07T14:16:00.000+02:00</published><updated>2007-06-07T14:33:30.969+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='ideas'/><title type='text'>LALR</title><content type='html'>&lt;div align="justify" style="margin-bottom: 10px;"&gt;&lt;span style="font-size: 107%; font-variant: small-caps;"&gt;¿Tiene alguno de vosotros&lt;/span&gt; código que funcione para un generador LALR? Sí, ya sé que hay unos proyectos por ahí equivalentes a yacc/bison... pero me llevaría demasiado tiempo retocarlo y adaptarlo. El tiempo que no tengo ahora.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;El caso es que tengo una idea de "producto": un generador de compiladores especialmente adaptado para .NET. ¿Cuál es el problema? Cuando se trata de compiladores .NET, o creas un compilador recursivo descendente, a mano (o con alguna ayuda de herramientas), o utilizas un analizador LALR(1), que suelen ser más potentes. Pero en este último caso, te encuentras un problema: el analizador suele llamar a un conjunto de rutinas para construir un árbol durante la compilación. Y esas rutinas por obligación reciben todos sus parámetros como valores de tipo &lt;b&gt;object&lt;/b&gt; o de alguna clase base más o menos igual de primitiva. Como resultado, tienes que estar ejecutando conversiones dinámicas de tipos todo el tiempo. No se trata tanto de la pérdida de velocidad, que al final no es tanta, sino de la pérdida de seguridad, robustez, etc, etc. En un entorno nativo, podías realizar conversiones estáticas (arriesgándote a recibir un error en ejecución si te equivocabas), pero esto no es posible en .NET.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;Hay otro problema: el modelo de desarrollo. Quien crea un compilador de esta manera tiene que programar, por una parte, la gramática "a secas". Luego de ejecutar la herramienta que la convierte en código ejecutable, tiene que ocuparse de establecer las correspondencias entre reglas de la gramática y rutinas semánticas. En sistemas más "primitivos", como el &lt;i&gt;yacc&lt;/i&gt;, podías escribir las rutinas junto con las reglas. Sin embargo, &lt;a href="http://www.devincook.com"&gt;GOLD Parser Builder&lt;/a&gt;, a pesar de ser una herramienta mucho más agradable de usar, sigue la filosofía de separar reglas y rutinas, en beneficio de la independencia del lenguaje.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;Mi idea es crear un generador de compiladores basado en un lenguaje propio, de estilo funcional (es lo más adecuado en estos casos). Para cada no terminal de la gramática, se establecería un tipo para los nodos que generaría. Entonces, el generador podría crear pilas separadas para cada uno de los tipos asociados a las reglas. Así se evitaría el problema de las conversiones.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;Por otra parte, por muy poca potencia que le des al lenguaje, se logra mucho. Como el objetivo de los "programas" es generar una estructura de datos arbórea, la mayoría de las llamadas serán a constructores. No es necesario que el lenguaje tenga "lazy evaluation", porque el algoritmo de análisis bottom-up garantiza que los parámetros de llamada a cada constructor ya estarán evaluados antes de esta llamada. Además, teniendo ya experiencia en compilar código para .NET sería extremadamente fácil que la herramienta crease directamente módulos o ensamblados, listos para utilizar, sin necesidad de pasar por un fichero intermedio con código fuente en otro lenguaje.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;¿Alguien se anima?&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-2063772769507982818?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/2063772769507982818/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=2063772769507982818&amp;isPopup=true' title='26 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2063772769507982818'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2063772769507982818'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/06/lalr.html' title='LALR'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>26</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-6866379560514590952</id><published>2007-06-05T14:02:00.000+02:00</published><updated>2007-06-05T14:08:00.497+02:00</updated><title type='text'>¿Cuánto son dos más dos?</title><content type='html'>&lt;div align="justify" style="margin-bottom: 10px;"&gt;... y ahora pretenderán que los que siempre respondimos "cuatro" nos alegramos de que finalmente no hayan sido cinco.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;Cuando yo no trabajo, no cobro. Pretender que en España alguien dimita por un error, aunque sea por tamaño error, es ser muy inocente. Pero al menos que no cobre. Que no cobre ni un duro de salario, que vaya a La Moncloa en el metro de Aguirre y Gallardón, que se olvide de los helicópteros del ejército para ir a ver los toros o a su mujer haciendo los coros, hasta que todos aquellos con los que ha estado impúdicamente coqueteando durante estos meses estén donde siempre debían haber estado: en la cárcel, o entre las seis tablas de madera de un paralelepípedo oblongo.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-6866379560514590952?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/6866379560514590952/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=6866379560514590952&amp;isPopup=true' title='15 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/6866379560514590952'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/6866379560514590952'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/06/cunto-son-dos-ms-dos.html' title='¿Cuánto son dos más dos?'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>15</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-5768759148727716746</id><published>2007-05-09T17:37:00.000+02:00</published><updated>2008-12-11T09:01:36.839+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Freya'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='AOP'/><title type='text'>Object triggers</title><content type='html'>&lt;div align="justify" style="margin-bottom: 10px;"&gt;&lt;span style="font-size: 107%; font-variant: small-caps;"&gt;Aunque es prematuro&lt;/span&gt;, todo sea por concretar un poco la idea:&lt;/div&gt;&lt;pre style="margin-left: 32px; margin-bottom: 2px; line-height: 110%;"&gt;&lt;i&gt;// Freya&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Editor = &lt;b&gt;class&lt;br /&gt;public&lt;br /&gt;    property&lt;/b&gt; CurrentPosition: Position;&lt;br /&gt;    &lt;b&gt;event&lt;/b&gt; PositionChanged: EventHandler;&lt;/pre&gt;&lt;pre style="margin-left: 32px; margin-bottom: 2px; line-height: 110%;"&gt;&lt;b&gt;protected&lt;br /&gt;    method&lt;/b&gt; OnPositionChanged; &lt;b&gt;virtual&lt;/b&gt;;&lt;br /&gt;    &lt;b&gt;begin&lt;br /&gt;        var&lt;/b&gt; eh := PositionChanged;&lt;br /&gt;        &lt;b&gt;if&lt;/b&gt; eh &lt;&gt; &lt;b&gt;nil then&lt;/b&gt;&lt;br /&gt;            eh(Self, EventArgs.Empty);&lt;br /&gt;    &lt;b&gt;end&lt;/b&gt;;&lt;/pre&gt;&lt;pre style="margin-left: 32px; margin-bottom: 2px; line-height: 110%;"&gt;&lt;b&gt;implementation&lt;/b&gt;&lt;/pre&gt;&lt;pre style="margin-left: 32px; margin-bottom: 2px; line-height: 110%;"&gt;    &lt;i&gt;// Este es un trigger: se admite read, write y execute.&lt;br /&gt;    // Pueden combinarse varios recursos en un mismo trigger.&lt;/i&gt;&lt;br /&gt;    &lt;b&gt;on&lt;/b&gt; CurrentPosition(write)&lt;br /&gt;    &lt;b&gt;var&lt;/b&gt;&lt;br /&gt;        &lt;i&gt;// Estas variables se convierten en campos&lt;/i&gt;&lt;br /&gt;        flag: Integer := 0;&lt;br /&gt;    &lt;b&gt;begin&lt;/b&gt;&lt;br /&gt;        flag++;&lt;br /&gt;        &lt;i&gt;// Esto sí es una verdadera variable local:&lt;/i&gt;&lt;br /&gt;        &lt;b&gt;var&lt;/b&gt; initialPosition := currentPosition;&lt;br /&gt;    &lt;b&gt;finally&lt;/b&gt;&lt;br /&gt;        flag--;&lt;br /&gt;        &lt;b&gt;if&lt;/b&gt; flag = 0 &lt;b&gt;then&lt;/b&gt;&lt;br /&gt;            &lt;b&gt;if&lt;/b&gt; initialPosition &lt;&gt; currentPosition &lt;b&gt;then&lt;/b&gt;&lt;br /&gt;            OnPositionChanged;&lt;br /&gt;    &lt;b&gt;end&lt;/b&gt;;&lt;/pre&gt;&lt;pre style="margin-left: 32px; margin-bottom: 10px; line-height: 110%;"&gt;&lt;b&gt;end&lt;/b&gt;;&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;&lt;img style="float:right; margin:1px 0 1px 8px;" src="http://1.bp.blogspot.com/_QWaXq7W8dVI/RkHvnMpBaiI/AAAAAAAAAA0/gBQJOlpKhh8/s320/trigger.jpg" border="0" alt="A trigger, what else?" /&gt;He intentado no meter palabras reservadas nuevas, al menos mientras no estén más claras las ideas. Lo que quiero averiguar es si con esta simple técnica se pueden lograr todas las cosas positivas de la AOP, sin provocar, a la misma vez, todos los problemas que ahora provoca. La clase, por supuesto, tendría mucho más código, y los &lt;i&gt;triggers&lt;/i&gt;, por llamarlos de algún modo, siempre van en la implementación de la clase (no interesan al cliente de la clase).&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;Importante: los campos usados por un &lt;i&gt;trigger&lt;/i&gt; son solamente visibles para el propio &lt;i&gt;trigger&lt;/i&gt;. Por ello puede usarse un nombre como &lt;i&gt;flag&lt;/i&gt; sin preocupaciones, porque de existir ya un miembro con este nombre, el campo se renombraría.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;Y por supuesto, la historia puede complicarse todo lo que se quiera: ¿se podrían heredar &lt;i&gt;triggers&lt;/i&gt; para aplicarse a nuevos recursos? Probablemente sí, en la medida en que el recurso protegido pueda ser modificado en una clase derivada. ¿Tiene sentido definir &lt;i&gt;triggers&lt;/i&gt; independientemente del recurso que protegen, para enlazarlos luego con un recurso en una implementación? Supongo que dependerá de la complejidad del código que pueda meterse en un &lt;i&gt;trigger&lt;/i&gt;.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;Observe también que, en general, podría vigilarse más de un recurso con el mismo &lt;i&gt;trigger&lt;/i&gt;. Imagine que, en vez de tener una variable (o una propiedad) que encapsula fila y columna, tenemos dos campos separados. En tal caso, el mismo &lt;i&gt;trigger&lt;/i&gt; se "tejería" para los métodos que modificasen &lt;i&gt;uno u otro campo&lt;/i&gt;. ¿Tiene sentido definir &lt;i&gt;triggers&lt;/i&gt; para que se apliquen cuando un método acceda a &lt;i&gt;uno y otro campo&lt;/i&gt;? No lo sé: tengo que encontrar un ejemplo con sentido. De esto, de encontrar más ejemplos, se trata ahora.&lt;/div&gt;&lt;hr&gt;&lt;div align="center" style="margin-bottom: 4px; font-size: 90%;"&gt;NOTAS&lt;/div&gt;&lt;div align="justify" style="margin: 0px 24px 10px 24px; font-size: 90%; font-style: italic; line-height: 135%;"&gt;A quien haya seguido ejemplos anteriores en Freya, le extrañará probablemente la implementación en línea del método &lt;font color="#408080"&gt;OnPositionChanged&lt;/font&gt;. No hay nada extraño: Freya sigue manteniendo el viejo formato, con las declaraciones en secciones &lt;b&gt;public&lt;/b&gt;/&lt;b&gt;private&lt;/b&gt; y secciones &lt;b&gt;implementation for&lt;/b&gt; para las implementaciones. Pero ahora también es posible utilizar el estilo en línea, como en Eiffel (y Java y C#). Observe, de paso, que incluso en tal caso sigue existiendo una sección &lt;b&gt;implementation&lt;/b&gt;, aunque en ella ya no se menciona la clase, por ser innecesario. En esta sección siguen residiendo los "detalles de implementación", que sería inapropiado situar en una sección "regular". Por ejemplo: constructores de clase (estáticos), delegaciones de implementación para tipos de interfaz, implementaciones explícitas de miembros de interfaces y destructores.&lt;/div&gt;&lt;div align="justify" style="margin: 0px 24px 10px 24px; font-size: 90%; font-style: italic; line-height: 135%;"&gt;Una vez aclarado este punto, observe que &lt;font color="#408080"&gt;CurrentPosition&lt;/font&gt; es una propiedad sin implementación explícita. En estos casos, el compilador declara un identificador oculto y genera automáticamente los métodos de acceso necesarios. Mejor aún: cuando se hace referencia a la propiedad dentro de la misma clase, ésta se sustituye por una referencia al campo. Y si la propiedad no es virtual, el campo oculto se declara &lt;b&gt;internal&lt;/b&gt;, y la optimización se realiza también para los usos de la propiedad dentro del propio ensamblado, con independencia de la clase. Si alguna vez se cuestiona la necesidad de Freya, recuerde que la calidad del código generado es muy superior a la media de los compiladores para .NET, a pesar de las limitaciones impuestas por la plataforma :)&lt;/div&gt;&lt;div align="justify" style="margin: 0px 24px 4px 24px; font-size: 90%; font-style: italic; line-height: 135%;"&gt;Otro pequeño detalle: observo cómo copio el valor del evento &lt;font color="#408080"&gt;PositionChanged&lt;/font&gt; antes de comprobar su valor y ejecutarlo. Es común ver por ahí código que no utiliza una variable temporal, pero aunque teóricamente es correcto, podemos tener problema si alguna vez accedemos al mismo objeto desde dos hilos paralelos. La técnica mostrada es la "correcta", teniendo en cuenta esta posibilidad.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-5768759148727716746?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/5768759148727716746/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=5768759148727716746&amp;isPopup=true' title='4 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/5768759148727716746'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/5768759148727716746'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/05/object-triggers.html' title='Object triggers'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_QWaXq7W8dVI/RkHvnMpBaiI/AAAAAAAAAA0/gBQJOlpKhh8/s72-c/trigger.jpg' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-3705262464230379237</id><published>2007-05-04T21:55:00.000+02:00</published><updated>2007-05-04T22:02:37.266+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Delphi'/><category scheme='http://www.blogger.com/atom/ns#' term='ideas'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><title type='text'>¿Por qué triunfa un lenguaje?</title><content type='html'>&lt;div align="justify" style="margin-bottom: 10px;"&gt;Es evidente que un lenguaje no siempre triunfa exclusivamente por sus méritos propios. De lo contrario, ¿cómo explicaríamos el larguísimo reinado de C++ y el injusto olvido de Eiffel?&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;En ocasiones, sin embargo, las causas del triunfo pueden ser sorprendentes, y puede que no hayan sido previstas por su autor. Lo digo porque acabo de recordar algo muy importante que influyó en mi decisión de usar Delphi como herramienta principal de programación... a pesar de conocer bien C++ y del estado más avanzado de este lenguaje y sus implementaciones por aquel entonces. No olvide que, a pesar de los méritos innegables de los genéricos de .NET, C++ tiene &lt;i&gt;templates&lt;/i&gt; desde tiempo inmemoriales, igual que Eiffel (y no digamos ya Ada).&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;Me voy a callar esta causa (hay muchas más, qué duda cabe) un tiempo. Si quiere contar la suya en los comentarios, las iré añadiendo a este post (para ser más concisos, utilice negritas, si quiere, para destacar la parte que quiere que copie). Y luego diré la mía, si nadie la menciona antes...&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-3705262464230379237?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/3705262464230379237/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=3705262464230379237&amp;isPopup=true' title='29 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/3705262464230379237'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/3705262464230379237'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/05/por-qu-triunfa-un-lenguaje.html' title='¿Por qué triunfa un lenguaje?'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>29</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-1742459388789485408</id><published>2007-05-04T18:47:00.000+02:00</published><updated>2007-05-04T18:51:18.019+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Freya'/><category scheme='http://www.blogger.com/atom/ns#' term='ideas'/><title type='text'>Una vieja buena idea</title><content type='html'>&lt;div align="justify" style="margin-bottom: 10px;"&gt;¿Cómo se escribe "un millón" en su lenguaje de programación favorito? En Freya, se escribe así:&lt;/div&gt;&lt;pre style="margin-left: 32px; line-height: normal;"&gt;1_000_000&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 4px;"&gt;La idea, naturalmente, no es nueva: creo que en Ada, como mínimo, hay algo parecido. Y en todo caso, la he copiado directamente de Eiffel. Sin embargo, ¿a que es útil?&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-1742459388789485408?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/1742459388789485408/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=1742459388789485408&amp;isPopup=true' title='8 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/1742459388789485408'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/1742459388789485408'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/05/una-vieja-buena-idea.html' title='Una vieja buena idea'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-4782329506115180539</id><published>2007-05-03T16:11:00.000+02:00</published><updated>2007-05-03T17:34:29.793+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Freya'/><category scheme='http://www.blogger.com/atom/ns#' term='ideas'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><title type='text'>Internal affaires</title><content type='html'>&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;span style="font-size: 107%; font-variant: small-caps;"&gt;¿Y si llevásemos la propuesta&lt;/span&gt; de &lt;a href="http://commanet.blogspot.com/2007/04/exportacin-selectiva.html"&gt;exportación selectiva&lt;/a&gt; aún más lejos? Quiero decir, ¿y si permitiésemos la mención de rutinas, propiedades y eventos en la lista de entidades con acceso a un recurso? Actualmente, en la sintaxis de Freya, la exportación selectiva tiene este aspecto:&lt;/div&gt;&lt;pre style="margin-left: 32px; line-height: normal;"&gt;MiClase = &lt;b&gt;class&lt;/b&gt;&lt;br /&gt;&lt;b&gt;internal&lt;/b&gt;(OtraClase, YOtraMas)&lt;br /&gt;    Campo: Integer;&lt;br /&gt;    &lt;i&gt;// ... etcétera ...&lt;/i&gt;&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;;&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Lo que ahora digo es esto otro:&lt;/div&gt;&lt;pre style="margin-left: 32px; line-height: normal;"&gt;MiClase = &lt;b&gt;class&lt;/b&gt;&lt;br /&gt;&lt;b&gt;internal&lt;/b&gt;(MiClase.Propiedad)&lt;br /&gt;    Campo: Integer;&lt;br /&gt;    &lt;i&gt;// ... etcétera ...&lt;/i&gt;&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;;&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Sí, este es un ejemplo "extremo": sólo permito que &lt;i&gt;Campo&lt;/i&gt; sea usado por el código de la propiedad &lt;i&gt;Propiedad&lt;/i&gt;... de la misma clase donde se ha definido &lt;i&gt;Campo&lt;/i&gt;. En circunstancias normales, no habría que caer en el "tremendismo", pero esto permite usar una técnica que he echado de menos en ocasiones. Por ejemplo, en el editor de código se define un campo privado para almacenar la posición del curso. En paralelo, se usa una propiedad para encapsular esta posición. El caso es que, cuando se cambia la línea activa, se producen cambios en el búfer de líneas interno. Sin embargo, es relativamente seguro modificar directamente la columna activa... y uno, que es un triste pecador, lo ha hecho en varias ocasiones. De haber tenido la disciplina suficiente, podría haber asociado un evento a las escrituras en la propiedad. Pero, ¿quién localiza, a estas alturas, todas las violaciones de esta "regla"? Con la posibilidad de reducir el uso de un campo a una propiedad, como propongo, sería muy sencillo, no ya cumplir con la regla, sino ponerla inmediatamente en conocimiento de quien lee el código.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Resumamos las bondades de mi propuesta:&lt;/div&gt;&lt;ul type="disc"&gt;&lt;li&gt;Se reduce fulminantemente la cantidad absoluta de dependencias potenciales entre clases, e incluso dentro de la misma clase.&lt;/li&gt;&lt;li&gt;Como esta técnica afecta solamente a las declaraciones internas, no hay peligro alguno de interacción con otros lenguajes .NET. Puedo seguir utilizando desde C# un ensamblado escrito en Freya, y viceversa.&lt;/li&gt;&lt;li&gt;Cuando en la lista de "entidades" a las que se le permite el acceso aparece una clase, se entiende que es lo mismo que &lt;i&gt;"Clase.*"&lt;/i&gt;: se le concede acceso a todos los miembros de la clase mencionada.&lt;/li&gt;&lt;li&gt;Este tipo de restricciones de acceso pueden interpretarse también como una modalidad de contrato ligado a la implementación de un recurso. Este tipo de contrato ya es muy popular entre los programadores, pero no existe una forma sencilla de hacerlo explícito.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;La visión reduccionista&lt;/h3&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Una reflexión al margen: otra solución al evento que falta en mi editor de código podría utilizar la Programación Orientada a Aspectos: podría indicar que, para todos los métodos que modifiquen la posición del cursor, se genere un prólogo en el que se memorice la posición inicial, y un epílogo que dispare el evento si se han producido cambios. Menciono esto porque es importante observar la gran diferencia entre la solución OOP y la solución AOP. Y la observación tiene que ver con el énfasis que pone la AOP &lt;i&gt;en el texto del programa&lt;/i&gt;. La visión OOP monta capas y más capas de abstracciones sobre las tiras de caracteres del programa, mientras que la visión AOP, al centrarse en el texto, se podría calificar incluso de &lt;i&gt;reduccionista&lt;/i&gt;.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Y no se trata de un mero florilegio retórico. Por una parte, está demostrado que la AOP resuelve algunos problemas (no todos) de manera más eficiente, sencilla y controlable que la OOP. Pero se trata de sustituir una cosa por la otra... porque no es ese el propósito de la AOP. Se trata de que este enfoque reduccionista puede aportar claridad a muchos debates viciados. Durante tiempo hemos intentado juzgar la OOP según sus propios reglas. ¿El resultado? Pues que cada vez es más difícil evaluar los méritos de las propuestas y novedades. Y por otra parte, vemos a autores a los que se le supone cierta seriedad defendiendo tonterías como el llamado &lt;i&gt;"duck typing"&lt;/i&gt;.&lt;/div&gt;&lt;div align="justify" style="font-size: 85%; font-style: italic; margin: 0px 32px 8px 32px;"&gt;¿Una pista sobre el impacto que puede tener la visión "reduccionista" en Informática? Ahí tiene el revuelo que han traido consigo las clases parciales de .NET 2.0. En principio, se trataría de un mero "truco" de ficheros... pero resulta que el "truco" ha encontrado aplicaciones de todo tipo. Y es que, al fin y al cabo, una de las grandes justificaciones de la OOP tiene que ver con la "mera" distribución del código fuente: en la programación estructurada original, se tendería a organizar el código de acuerdo a su función, mientras que en la OOP, el código se agruparía respecto al "propietario" de cada método. Eso facilitaría la adición de nueva funcionalidad: observe que se trata de una justificación textual y reduccionista.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 2px;"&gt;Bienvenido sea el reduccionismo...&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-4782329506115180539?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/4782329506115180539/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=4782329506115180539&amp;isPopup=true' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/4782329506115180539'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/4782329506115180539'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/05/internal-affaires.html' title='Internal affaires'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-2483876365266374918</id><published>2007-04-30T00:33:00.000+02:00</published><updated>2007-04-30T00:36:33.748+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Freya'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><title type='text'>Espada afilada</title><content type='html'>&lt;img style="display:block; margin:0px auto 10px; text-align:center;" src="http://www.marteens.com/freya/images/blade.gif" border="0" alt="Sharp Blade" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-2483876365266374918?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/2483876365266374918/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=2483876365266374918&amp;isPopup=true' title='12 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2483876365266374918'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/2483876365266374918'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/04/espada-afilada.html' title='Espada afilada'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-8248254220685753815</id><published>2007-04-16T21:43:00.001+02:00</published><updated>2007-04-17T15:10:11.686+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bases de datos'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><title type='text'>La prima de un amigo de mi cuñada</title><content type='html'>&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;img src="http://www.marteens.com/adv/chain.png" border="0" alt="Cadena de conocidos" style="float: right; margin: 1px 0px 1px 8px;" /&gt;&lt;span style="font-size: 107%; font-variant: small-caps;"&gt;Según una popular leyenda&lt;/span&gt; urbana, entre usted y cualquier otra persona, sin importar el país de esta última, existe una cadena de conocidos que es sorprendentemente corta: usted conoce a Fulano, quien a su vez conoce a Mengano, el primo de Zutano, aquel que es amigo de la peluquera de Drew Barrymore. La longitud de la cadena, por supuesto, depende de quién cuente la historia. En todo caso, es una leyenda en la que creo. ¿Qué tal siete eslabones?&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;¿Y si este fenómeno tuviese en parte la culpa de que las bases de datos orientadas a objetos no hayan prosperado como predecía la teoría? Podrían combinarse negativamente dos factores:&lt;/div&gt;&lt;ol&gt;&lt;li&gt;Por una parte, estaría lo que acabo de explicar: que en la mayoría de los esquemas de datos, hay tanta imbricación que, un sistema de bases de datos orientado a objetos implementado ingenuamente, podría saturar en muy poco tiempo la memoria dinámica, trayendo a ésta casi todos los registros.&lt;/li&gt;&lt;li&gt;En principio, habría técnicas para evitar esto, utilizando carga por demanda... pero, ¿se da cuenta de que estamos hablando de clases y objetos, y por lo tanto, de encapsulación? Si enredamos demasiado con las relaciones estructurales, entraremos en conflicto con la encapsulación.&lt;/li&gt;&lt;/ol&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;No estoy diciendo que ésta, en concreto, sea la única causa, ni la principal. Se me ha ocurrido esta posibilidad mientras pensaba en los pros y contras de un sistema como LINQ: me parece que el principal y casi seguro logro de LINQ va a ser que dispondremos de unos &lt;i&gt;datasets&lt;/i&gt; estupendos, aunque no los llamemos así en lo sucesivo. Habrá que esperar a la implementación de los árboles de expresiones para ver qué tal se comporta la recuperación de registros desde un servidor SQL: como, de todas maneras, el servidor SQL optimizará la consulta recibida, es casi seguro que, incluso en el peor de los escenarios, funcione bien. Y todo esto es bueno y deseable. Pero nada de esto no nos acerca a las bases de datos orientadas a objetos. Y puede que esto último también sea bueno y deseable.&lt;/div&gt;&lt;hr style="border-style:dashed; border-color:#b0d0f0; height:1px;"&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;b&gt;Corolario&lt;/b&gt;: Entre usted y los extraterrestres hay al menos una cadena de ocho eslabones.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;b&gt;Demostración&lt;/b&gt;: Entre usted y Drew Barrymore hay una cadena de no más de siete eslabones. Y Drew Barrymore conoce a E.T.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-8248254220685753815?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/8248254220685753815/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=8248254220685753815&amp;isPopup=true' title='6 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/8248254220685753815'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/8248254220685753815'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/04/la-prima-de-un-amigo-de-mi-cuada.html' title='La prima de un amigo de mi cuñada'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-4450122550958655204</id><published>2007-04-14T15:44:00.000+02:00</published><updated>2007-04-16T15:07:16.756+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='libros'/><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>En el radar</title><content type='html'>&lt;div align="justify" style="margin-bottom: 12px;"&gt;Próxima actualización en el radar: nueva entrega de Intuitive C#. Hay un nuevo capítulo sobre P.O.O. (el segundo), que no cuenta nada nuevo, pero lo que cuenta está más o menos bien escrito. O eso creo. Hay más información sobre reflexión, tipos de interfaz, genericidad, inferencia de tipos en llamadas a métodos genéricos, expresiones lambda (¡sí, las de C# 3.0!), qué es una &lt;i&gt;restricción desnuda&lt;/i&gt; y cómo puede usarse para simular la covarianza en la asignación polimórfica de tipos genéricos, convirtiendo, por ejemplo, una lista de empleados en una lista de personas (y provocando una excepción cuando encuentre un abogado en ella)...&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 12px;"&gt;No, todavía no lo he subido a Internet. Ya avisaré, probablemente el lunes que viene.&lt;/div&gt;&lt;hr style="border-style:dashed; border-color:#bfdff0; height:1px;"&gt;&lt;div align="justify" style="margin-bottom: 12px;"&gt;Un comentario breve sobre C# 3.0: no me gusta la forma de "activar" los &lt;i&gt;métodos de extensión&lt;/i&gt;. Esto ya lo tenía Delphi.NET 8.0: podías fingir que una clase ajena tenía métodos adicionales definiendo esos nuevos métodos como métodos estáticos cuyo primer parámetro tenga el tipo de la clase a extender. Así, Borland intentaba acercar el &lt;i&gt;System.Object&lt;/i&gt; de .NET con el &lt;i&gt;TObject&lt;/i&gt; délfico de siempre.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 12px;"&gt;En Freya ya hay unas pocas extensiones predefinidas. Por ejemplo, hay dos extensiones que se expanden en línea: los "métodos" &lt;i&gt;Sqr&lt;/i&gt;, que actúa sobre tipos numéricos, y &lt;i&gt;Ord&lt;/i&gt;, que convierte caracteres en su valor numérico Unicode:&lt;/div&gt;&lt;pre style="MARGIN: 0px 0px 8px 24px; LINE-HEIGHT: normal"&gt;Console.WriteLine(2.Sqr);&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 12px;"&gt;El compilador genera código muy eficiente para &lt;i&gt;Sqr&lt;/i&gt;: una instrucción de duplicación y la multiplicación. En una aplicación como XSight RT, donde hay que elevar expresiones complejas al cuadrado constantemente, no sólo queda más legible el código fuente, sino que además, se genera mejor código nativo, y el compilador JIT tiene menos carga y termina antes, al serle más sencillo identificar el patrón. Aparte de esto, se considera que todos los métodos estáticos de la clase &lt;i&gt;System.Math&lt;/i&gt; se registran automáticamente como métodos de extensión. Así podemos escribir lo siguiente en Freya:&lt;/div&gt;&lt;pre style="MARGIN: 0px 0px 8px 24px; LINE-HEIGHT: normal"&gt;&lt;b&gt;var&lt;/b&gt; L := (X.Sqr + Y.Sqr + Z.Sqr).Sqrt;&lt;br /&gt;&lt;b&gt;if&lt;/b&gt; (L - L0).Abs &lt; epsilon &lt;b&gt;then&lt;/b&gt;&lt;br /&gt;    &lt;i&gt;// ...&lt;/i&gt;&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 12px;"&gt;Lo que no me gusta es la forma en que se "activan" los métodos de extensión en C#: basta con incluir el espacio de nombres en una cláusula &lt;b&gt;using&lt;/b&gt;, para que todos los métodos de extensión de ese espacio de nombre entren en danza. Lo malo: un espacio de nombre es una entidad sin "chicha" en .NET. Pueden definirse tipos para un espacio de nombre en más de un ensamblado. De modo que al incluir el &lt;b&gt;using&lt;/b&gt;, estamos activando todas extensiones, sin importar en qué ensamblado vengan. Además, la cláusula &lt;b&gt;using&lt;/b&gt; ya tiene su propia función. Pueden surgir casos en los que nos interese el uso normal y no el extendido. Por supuesto, con mucho cuidado, no tendrían que surgir problemas... pero no deja de ser chapucero.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-4450122550958655204?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/4450122550958655204/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=4450122550958655204&amp;isPopup=true' title='7 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/4450122550958655204'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/4450122550958655204'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/04/en-el-radar.html' title='En el radar'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-5875463738259553995</id><published>2007-04-10T12:03:00.000+02:00</published><updated>2008-12-11T09:01:37.057+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><title type='text'>Exportación selectiva</title><content type='html'>&lt;div align="justify" style="margin-bottom: 12px;"&gt;&lt;img style="float:right; margin:1px 0 1px 10px;" src="http://4.bp.blogspot.com/_QWaXq7W8dVI/RhuBtMhG0BI/AAAAAAAAAAs/xjILXV2Bww4/s320/eye.jpg" border="0" alt="Visibility" /&gt;&lt;span style="font-size: 107%; font-variant: small-caps;"&gt;Mientras releo el código&lt;/span&gt; fuente del &lt;a href="http://commanet.blogspot.com/2007/03/docking.html" target="_blank"&gt;sistema de ventanas&lt;/a&gt; que mencionaba hace unos días, me reafirmo en mi idea sobre cuál es la primera característica que le añadiría a los lenguajes .NET: la &lt;i&gt;exportación selectiva&lt;/i&gt; de sus miembros.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 12px;"&gt;Esta idea, como tantas otras, la conozco a través de Eiffel. En las clases de este lenguaje no existen las típicas secciones &lt;b&gt;private&lt;/b&gt;, &lt;b&gt;public&lt;/b&gt; o &lt;b&gt;protected&lt;/b&gt;, popularizadas por C++. Los miembros de una clase se agrupan en secciones encabezadas por la palabra clave &lt;b&gt;feature&lt;/b&gt; (debería tener una "s" final para estar en tercera persona del singular; lo mismo ocurre con &lt;i&gt;require&lt;/i&gt; o &lt;i&gt;ensure&lt;/i&gt;). Estas cabeceras de sección pueden incluir una lista de clases que pueden utilizar los miembros agrupados bajo ella:&lt;/div&gt;&lt;pre style="margin-left: 32px; line-height: normal;"&gt;&lt;b&gt;class&lt;/b&gt; FULANA&lt;br /&gt;&lt;b&gt;feature&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;feature&lt;/b&gt; &lt;font color="navy"&gt;{ MENGANA, ZUTANA }&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;feature&lt;/b&gt; &lt;font color="navy"&gt;{ NONE }&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 12px;"&gt;La idea que me ronda no es eliminar el actual sistema de niveles de acceso. En principio, sólo sería necesario ampliar las posibilidades del nivel &lt;b&gt;internal&lt;/b&gt;. Ahora mismo, cualquier miembro declarado &lt;b&gt;internal&lt;/b&gt; está al alcance de cualquier otra clase definida en el mismo ensamblado. Barra libre, por así decirlo. Imposible saber quién está toqueteando indebidamente el método &lt;i&gt;X&lt;/i&gt; y por qué razón lo hace. Menos mal que existe un comando &lt;i&gt;Buscar todas las referencias&lt;/i&gt;... pero no es lo mismo.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 12px;"&gt;Lo peor de todo es que existen poderosos motivos para que un programador decida declarar métodos y propiedades internas... cargándose la mantenibilidad del sistema que está programando. Usted ha comenzado a programar su sistema como una aplicación monolítica. Luego se ha dado cuenta de que puede manejar la aplicación desde otra aplicación independiente: basta con utilizar el ejecutable como si fuese una biblioteca de clases. El compilador de línea de comandos de Freya, por ejemplo, es un fichero ejecutable que implementa una aplicación de consola, pero el entorno de desarrollo carga el ejecutable como si se tratase de un ensamblado en formato DLL. El problema es que, casi siempre, las clases dentro del ejecutable habrán sido originalmente diseñadas como clases públicas. Bien, usted esconde las clases &lt;i&gt;A&lt;/i&gt; y &lt;i&gt;B&lt;/i&gt; pero, ¡qué mala pata!, la clase &lt;i&gt;C&lt;/i&gt; tiene una propiedad pública que devuelve un objeto de tipo &lt;i&gt;A&lt;/i&gt;. No podemos redeclarar esa propiedad como privada, porque medio programa la utiliza... pero tampoco nos interesa que esté al alcance de cualquier mindundi. ¿La solución? El programador redeclara la propiedad como &lt;b&gt;internal&lt;/b&gt;... sin darse cuenta de que acaba de hundirse hasta la cintura en el fango.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 12px;"&gt;Mi propuesta consiste en mantener la misma sintaxis y semántica que ahora tienen los restantes niveles de visibilidad en .NET, y además permitir que el modificador &lt;b&gt;internal&lt;/b&gt; pueda ir acompañado por una lista de clases. Tenga presente que el efecto de &lt;b&gt;internal&lt;/b&gt; se limita al ensamblado donde se declara. Por lo tanto, este tipo de propuesta es ideal: se logra un efecto muy beneficioso sin necesidad de afectar el funcionamiento de los lenguajes de la plataforma que decidan no secundar la idea.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-5875463738259553995?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/5875463738259553995/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=5875463738259553995&amp;isPopup=true' title='10 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/5875463738259553995'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/5875463738259553995'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/04/exportacin-selectiva.html' title='Exportación selectiva'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_QWaXq7W8dVI/RhuBtMhG0BI/AAAAAAAAAAs/xjILXV2Bww4/s72-c/eye.jpg' height='72' width='72'/><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-8931392083312684396</id><published>2007-04-09T13:46:00.000+02:00</published><updated>2007-04-09T13:49:34.912+02:00</updated><title type='text'>Aviso: si has comprado un pack ISSE/Intuitive Delphi</title><content type='html'>Si has comprado un pack IntSight's Server Explorer/Intuitive Delphi el tres de este mes, por favor, ponte en contacto conmigo por email. El mensaje de confirmación de la compra, con los datos para la zona de descargas, me está rebotando constantemente con "problemas permanentes en la cuenta".&lt;br /&gt;&lt;br /&gt;El CD está, de todos modos, en camino, pero estando la Semana Santa por medio, puede aún tardar en llegar (este producto se envía por correo, no por mensajería).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-8931392083312684396?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/8931392083312684396/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=8931392083312684396&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/8931392083312684396'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/8931392083312684396'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/04/aviso-si-has-comprado-un-pack.html' title='Aviso: si has comprado un pack ISSE/Intuitive Delphi'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-3382928082691506021</id><published>2007-04-09T12:23:00.000+02:00</published><updated>2007-04-09T12:52:21.587+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='.NET'/><title type='text'>Tres punto cinco...</title><content type='html'>... y una pequeña corrección a los comentarios: será .NET 3.5.&lt;br /&gt;&lt;br /&gt;Ese es el número de versión que aparece en la beta de Orcas (vaya nombrecito): el Visual Studio 2007, por llamarlo de algún modo. Lo cierto es que toda esta complicación es culpa de la propia Microsoft, que ha tenido que hacer filigranas con las fechas de salida del Windows Vista y el número de versión de .NET para esa familia de productos.&lt;br /&gt;&lt;br /&gt;De todos modos, que no cunda el pánico: .NET 3.0 tiene novedades interesantes, pero ninguna que afecte "profundamente" al desarrollo de bases de datos. Al menos, ninguna que empuje a los renuentes a saltar al carro. Mi consejo es el obvio: hay que ser prudentes con la adopción de WFC. No porque tenga algún problema, sino por tratarse de una novedad ligada a una versión específica del sistema operativo (no es exactamente así, pero para abreviar...).&lt;br /&gt;&lt;br /&gt;También sería buena la prudencia respecto a LINQ, el nuevo ADO.NET Entity Framework y esas cosas, aunque por motivos diferentes. La adopción de estas nuevas técnicas no está limitada por la base de instalaciones de un sistema operativo: afectan solamente al programador, y si funcionan bien, nada impide que salte al vagón. Mi impresión, de momento, es positiva... pero repito, hay que ser prudentes. Puede que esta vez estemos frente a la técnica que domestique, de una vez por todas, los famosos "persistency frameworks", pero me asusta ver a gente que tenía por sensata (no, no estoy regañando a ninguno de nosotros) quemar tanto incienso por las extensiones al lenguaje inspiradas por la programación funcional.&lt;br /&gt;&lt;br /&gt;El problema consiste en que, para que toda esta historia funcione, no basta con que Anders Hejlsberg sea un monstruo de los lenguajes: hace falta que el equipo completo que tiene que escribir las clases de soporte para tiempo de ejecución haga bien las cosas. Y aunque, repito, creo que todo va a salir bien y que va a ser un producto estupendo, no puedo olvidar que la idea de los "Object Spaces" ha estado dando tumbos desorientada por todo el campus de Microsoft hasta que Hejlsberg y compañía se han atrevido a agarrar el toro por los cuernos.&lt;br /&gt;&lt;br /&gt;Ideas para superar el famoso "impedance mismatch" existen desde que se inventó la palabreja de marras. Suelen parecer ideas sencillas y, por lo mismo, geniales... pero hasta ahora, el monstruo que pretenden matar goza de buena salud. Es muy probable, diría que casi seguro, que esta vez sea la definitiva. Pero le aconsejo que no contenga la respiración hasta entonces...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-3382928082691506021?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/3382928082691506021/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=3382928082691506021&amp;isPopup=true' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/3382928082691506021'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/3382928082691506021'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/04/tres-punto-cinco.html' title='Tres punto cinco...'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-5108926553584557107</id><published>2007-03-27T15:44:00.000+02:00</published><updated>2007-03-27T16:07:52.521+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cursos'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Docking</title><content type='html'>&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;span style="font-size: 107%; font-variant: small-caps;"&gt;... sí, estoy con el curso de ADO.NET&lt;/span&gt;. Uno de los problemas que tenía con la serie D, sobre todo, era la dependencia de componentes de terceros para lograr una aplicación final "presentable". Oh, sí, lo importante es el interior, bla, bla... pero lo cierto es que ver una aplicación con los componentes de .NET v1.1 a secas es bastante descorazonador.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Y no sólo eso: buena parte del contenido de la serie D está relacionado con el gestor de ventanas. ADO.NET es relativamente sencillo, pero puede resultar laborioso, especialmente para coordinar navegación y actualización... si usas conjuntos de datos, claro, porque si no, da aún más trabajo. En concreto, lo que me preocupaba era precisamente el sistema de ventanas, que era bastante primitivo. Ahora mismo, la moda son las ventanas flotantes, esas otras ventanas escurridizas, los paneles de tareas, etc, etc. Tenía dos alternativas: serie D sin pitos ni flautas, otra vez, o serie D con componentes de terceros. Otra vez.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Como el mundo no es en blanco y negro, me he decidido por una tercera posibilidad: echar mano de alguna suite gratuita para el manejo de ventanas. Y la que he elegido, si no surge algún impedimento gordo, es la de &lt;a href="http://sourceforge.net/projects/dockpanelsuite" target="_blank"&gt;Weifen Luo&lt;/a&gt;. Estos componentes imitan el comportamiento de las ventanas de VS2005, son fáciles de usar, y son los que utilizan en &lt;a href="http://www.icsharpcode.net/OpenSource/SD/" target="_blank"&gt;SharpDevelop&lt;/a&gt; para el "ventaneo".&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Eso sí: es muy probable que "congele" una versión estable, en vez de buscar siempre la última. Además, aunque los componentes son muy estables, el código fuente no es exactamente el tipo de código que prefiero. Aunque muy estructurado, "todos hablan con todos": la comunicación entre módulos se produce a través de clases, y hay montones de declaraciones &lt;b&gt;internal&lt;/b&gt; dentro de cada clase. Es muy difícil detectar todas las dependencias y todos los canales de comunicación. Además, el autor ha usado tipos anidados y herencia... con ancestros y descendientes anidados en tipos no relacionados, con lo cuál complica mucho más entender qué demonios hace el código fuente.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Para rejillas y menúes, por supuesto, voy a usar los propios de VS2005, que funcionan muy bien. Respecto a los paneles de tareas (los famosos &lt;i&gt;task panels&lt;/i&gt;), creo que puedo vivir sin ellos. De todos modos, he visto un par de componentes gratuitos por ahí, y en el peor de los casos, no es complicado escribir uno propio (en IntSight Controls hay un grupo de componente de ese tipo, para Windows nativo, y dibujando todo a mano).&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-5108926553584557107?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/5108926553584557107/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=5108926553584557107&amp;isPopup=true' title='5 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/5108926553584557107'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/5108926553584557107'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/03/docking.html' title='Docking'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-1326116963142251528</id><published>2007-03-19T20:56:00.000+01:00</published><updated>2007-03-19T20:58:29.515+01:00</updated><title type='text'>Time break</title><content type='html'>Llevo un par de días en reposo por enfermedad. Nada grave (ni siquiera contagioso, sniff), pero me han mandado al banquillo. A ver si ya puedo retomar todos los asuntos pendientes esta semana...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-1326116963142251528?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/1326116963142251528/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=1326116963142251528&amp;isPopup=true' title='7 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/1326116963142251528'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/1326116963142251528'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/03/time-break.html' title='Time break'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-7456637076927059570</id><published>2007-03-12T15:35:00.000+01:00</published><updated>2007-03-12T15:40:38.255+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ideas'/><category scheme='http://www.blogger.com/atom/ns#' term='personajes'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><title type='text'>La importancia de llamarse Bertrand</title><content type='html'>&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;span style="font-size: 107%; font-variant: small-caps;"&gt;Para quienes todavía creen&lt;/span&gt; que hay algo oscuro, siniestro e inconfesable tras mi recomendación de .NET, he reencontrado este artículo en Internet:&lt;/div&gt;&lt;ul type="square"&gt;&lt;li&gt;&lt;a href="http://archive.eiffel.com/doc/manuals/technology/bmarticles/sd/dotnet.html" target="_blank"&gt;The Significance of .NET&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Espero que esos pocos conozcan quién es Bertrand Meyer.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-7456637076927059570?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/7456637076927059570/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=7456637076927059570&amp;isPopup=true' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7456637076927059570'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7456637076927059570'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/03/la-importancia-de-llamarse-bertrand.html' title='La importancia de llamarse Bertrand'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-675688171751301275</id><published>2007-03-05T19:25:00.000+01:00</published><updated>2008-12-11T09:01:37.259+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='interface'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='OOP'/><title type='text'>Intermezzo técnico</title><content type='html'>&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;img style="float:right; margin:1px 0 1px 8px;" src="http://2.bp.blogspot.com/_QWaXq7W8dVI/RexqXAFT8kI/AAAAAAAAAAg/SJCqX29ToI4/s320/intf.jpg" border="0" /&gt;&lt;span style="font-size: 107%; font-variant: small-caps;"&gt;¿Me permite un pequeño&lt;/span&gt; descanso antes de continuar con la serie sobre ideologías? En el último post sobre Freya, en los comentarios, Daniel Alvarez me señalaba unos artículos en Internet sobre integración con Visual Studio, en la Bitwise Magazine inglesa. Me llamó la atención, merodeando por dicha página, el siguiente artículo:&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.bitwisemag.com/2/The-Great-OOP-Debate"&gt;The Great OOP Debate (Bitwise Magazine)&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Cuidado, no estoy diciendo que esté de acuerdo con todo lo que se dice en el artículo. En realidad, creo que las opiniones de Huw y Dermot son muy diferentes, y en ocasiones incluso hablan de cosas muy diferentes sin darse cuenta.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Lo que quiero destacar es la importancia que Dermot concede al uso de interfaces... aunque en su caso, se refiere concretamente a las interfaces COM. Destaco esta opinión (basada en la práctica) porque coincide con lo que he podido comprobar por cuenta propia en estos últimos años... y que difiere radicalmente de las recomendaciones de Microsoft sobre el uso de tipos de interfaz.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;En concreto, me gusta plantear la funcionalidad y arquitectura de un sistema mediante un conjunto pequeño de interfaces. Luego, las clases entran en escena, pero sólo como un recurso de implementación. Por ejemplo, el compilador de Freya está basado en unas pocas interfaces como &lt;i&gt;ISymbolTable&lt;/i&gt;, &lt;i&gt;ICodeGenerator&lt;/i&gt; e &lt;i&gt;IParser&lt;/i&gt; que son luego implementadas por clases que funcionan como &lt;i&gt;singletons&lt;/i&gt; dentro de una instancia del compilador. Luego tenemos interfaces como &lt;i&gt;IAstNode&lt;/i&gt;, &lt;i&gt;IStatement&lt;/i&gt; e &lt;i&gt;IExpression&lt;/i&gt;, que son implementadas luego por una larga colección de clases. Lo importante es que toda comunicación entre módulos se especifica por medio de tipos de interfaz: el canal de comunicación que abren las interfaces es mucho más estrecho que el de las clases. Y la misma situación se da en Proteus, en XSight RT...&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;¿Mi consejo? Lea, analice, experimente y compare. Y luego, cuando decida, cuéntenos su decisión.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-675688171751301275?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/675688171751301275/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=675688171751301275&amp;isPopup=true' title='18 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/675688171751301275'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/675688171751301275'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/03/intermezzo-tcnico.html' title='Intermezzo técnico'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_QWaXq7W8dVI/RexqXAFT8kI/AAAAAAAAAAg/SJCqX29ToI4/s72-c/intf.jpg' height='72' width='72'/><thr:total>18</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-6046982554351400433</id><published>2007-03-05T12:07:00.000+01:00</published><updated>2008-12-11T09:01:37.682+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ideas'/><title type='text'>Ideologías - primera parte</title><content type='html'>&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;img style="float:right; margin:1px 0 1px 8px;" src="http://3.bp.blogspot.com/_QWaXq7W8dVI/RewKvQFT8jI/AAAAAAAAAAY/-SDqqYv00hQ/s320/robodog.jpg" border="0" alt="¿Sueña Aibo con perseguir y morder a Doraemon?" /&gt;&lt;span style="font-size: 107%; font-variant: small-caps;"&gt;No es lo más sorprendente&lt;/span&gt; de lo que me he encontrado en esta vida, pero como mínimo es curioso. Me refiero a la supuesta asociación que ven algunos entre software e ideología. Las ideologías actúan como filtros para evitar que la gente piense... y me refiero tanto a ideologías "laicas" como a ideologías relacionadas con religiones. ¿Cree usted que los humanos buscamos la verdad? No: lo que hacemos es coleccionar ideas que nos hacen sentir bien. Es cierto que las ideas verdaderas tienen el efecto secundario de hacernos sentir bien, como el "eureka" de Arquímedes. Y desechamos, por supuesto, aquellas que nos hacen sentir mal... muchas veces simplemente porque contradicen otras ideas que nos hacen sentir bien. ¿Parece una obviedad? Dígaselo a Searle, y a Noam Chomski, y a tantos otros que se ganan la vida filosofando "seriamente" sobre la mente y la voluntad, e ignoran estas trivialidades.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Hagamos una prueba. Dígame, rápido: ¿es buena medida subir el salario mínimo interprofesional?&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;La respuesta, en el siguiente post de esta serie.&lt;/div&gt;&lt;div style="margin-left: 32px; margin-right: 32px; font-size: 85%; font-style: italic;"&gt;... y sí, al final veremos qué tiene que ver todo esto con el software y la Informática. Sea paciente.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-6046982554351400433?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/6046982554351400433/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=6046982554351400433&amp;isPopup=true' title='8 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/6046982554351400433'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/6046982554351400433'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/03/ideologas-primera-parte.html' title='Ideologías - primera parte'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_QWaXq7W8dVI/RewKvQFT8jI/AAAAAAAAAAY/-SDqqYv00hQ/s72-c/robodog.jpg' height='72' width='72'/><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-8284538634669738109</id><published>2007-03-01T11:01:00.000+01:00</published><updated>2007-03-03T20:52:58.849+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='náusea'/><title type='text'>Impuestos atenuados</title><content type='html'>&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;span style="font-size: 107%; font-variant: small-caps;"&gt;Ya sé que está mal&lt;/span&gt; visto hablar de política. Pero esta mañana me he despertado y me he preguntado dónde estoy, qué hago aquí y todas esas reacciones que suelen provocar la incredulidad y la sorpresa.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;En definitiva, veamos el lado positivo del asunto: ¿creéis que, si me declaro en huelga de hambre, este gobierno me perdonará los impuestos, o me impondrá unos "impuestos atenuados"? ¿O tengo que asesinar primero a veinticinco personas?&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Sí, ya sé que no debo hablar sobre política, pero pensé que más que con la política, tenía que ver con la &lt;b&gt;decencia&lt;/b&gt;... sí, esa palabra todavía sale en el diccionario.&lt;/div&gt;&lt;hr&gt;&lt;div align="justify"&gt;Me han avisado que hay concentración hoy, &lt;b&gt;frente al Ministerio del Interior&lt;/b&gt;, en el &lt;b&gt;Paseo de la Castellana nº 5&lt;/b&gt;, a las &lt;b&gt;8 de la noche&lt;/b&gt;. Si me da tiempo, que creo que sí, me pasaré. Y me vais a perdonar por mi "activismo" en este tema, pero el asunto es gravísimo, y no se trata siquiera de política. Veinticinco asesinados por un terrorista. Dos chicos ecuatorianos asesinados en la Terminal 4 de Barajas hace un mes. Esto no tiene nombre. O sí...&lt;/div&gt;&lt;hr&gt;&lt;div style="margin-bottom: 12px;"&gt;Citas de la vida "real":&lt;/div&gt;&lt;div align="justify" style="font-size: 90%; font-style: italic; margin-left: 32px; margin-right: 32px; margin-bottom: 12px;"&gt;"No es nuestro miedo ni nuestra debilidad lo que le ha salvado, es nuestro valor de luchar por lo que creemos, que es la vida". (ZP)&lt;/div&gt;&lt;div style="margin-bottom: 12px;"&gt;Fragmento de "1984", la famosa novela de Orwell:&lt;/div&gt;&lt;div align="justify" style="font-size: 90%; font-style: italic; margin-left: 32px; margin-right: 32px; margin-bottom: 12px;"&gt;His mind slid away into the labyrinthine world of doublethink. To know and not to know, to be conscious of complete truthfulness while telling carefully-constructed lies, to hold simultaneously two opinions which cancelled out, knowing them to be contradictory and believing in both of them; to use logic against logic, to repudiate morality while laying claim to it, to believe that democracy was impossible and that the Party was the guardian of democracy; to forget whatever it was necessary to forget, then to draw it back at the moment when it was needed, and then promptly to forget it again: and above all, to apply the same process to the process itself. That was the ultimate subtlety: consciously to induce unconsciousness, and then, once again, to become unconscious of the art of hypnosis you had just performed. Even to understand the word 'doublethink' involved using doublethink.&lt;/div&gt;&lt;div&gt;La debilidad es fuerza, la ignorancia es sabiduría, la cobardía es valor, la esclavitud es libertad. Bienaventurados estos pobres de espíritu. Nunca ha estado tan claro: quien te promete un futuro, es porque te está robando el presente.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-8284538634669738109?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/8284538634669738109/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=8284538634669738109&amp;isPopup=true' title='8 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/8284538634669738109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/8284538634669738109'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/03/impuestos-atenuados.html' title='Impuestos atenuados'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-3015439220143653747</id><published>2007-02-28T19:53:00.000+01:00</published><updated>2007-02-28T21:36:00.828+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Freya'/><title type='text'>for var f in foes do</title><content type='html'>&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;span style="font-size: 107%; font-variant: small-caps;"&gt;No está mal para&lt;/span&gt; el típico &lt;i&gt;splash&lt;/i&gt; del IDE de pruebas, ¿o no?&lt;/div&gt;&lt;br /&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;" src="http://www.marteens.com/freya/images/freya.jpg" border="0" alt="Freya: Sharp Blade" /&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;Es verdad que la chica tiene cara de enfado. Da la impresión de estar pensando algo así como: &lt;i&gt;"al próximo que me pregunte si Marteens cobra de Microsoft por recomendar .NET le rebano la cabeza"&lt;/i&gt;...&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;He hecho el dibujo aprovechando el paso del IDE de pruebas para Freya, de su primera versión SDI (Hammer, es decir, &lt;i&gt;martillo&lt;/i&gt;) a la nueva versión MDI/tabbed pages. Había que darle un nombre, sobre todo para los proyectos no se llamen &lt;i&gt;freya01&lt;/i&gt;, &lt;i&gt;freya02&lt;/i&gt; y así hasta el aburrimiento, y ya que teníamos &lt;i&gt;anvil&lt;/i&gt; (el yunque), para el editor de código, y el ya mencionado &lt;i&gt;hammer&lt;/i&gt;, lo lógico era usar otro artilugio relacionado con los herreros. Nombre elegido: &lt;b&gt;Sharp Blade&lt;/b&gt;, es decir, &lt;i&gt;hoja o espada afilada&lt;/i&gt;. No está mal... Ya sé que CodeGear nunca reconocerá que mi compilador es mejor que el de ellos, pero al menos podrían contratarme para decidir los nombres de proyectos. Mira que usar nombres de culebras, coño...&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;... y sí, ya sé que el dibujo tiene fallos: no pienso dedicarme a estas alturas de la vida a las artes gráficas. De todos modos, me sorprende precisamente por eso: de repente "vi" la imagen mentalmente, me senté con mi &lt;a href="http://www.xara.com" target="_blank"&gt;Xara Xtreme Pro&lt;/a&gt; una hora, aproximadamente, y hala, dibujo casi terminado. La chica está dibujada "de memoria", y se parece mucho a una amiga que hace tiempo no veo. El pelo necesita más detalles, y también el labio superior. Ya lo arreglaré cuando vuelva a tener una hora de libertad.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 10px;"&gt;Recuerde: &lt;b&gt;Sharp Blade&lt;/b&gt;...&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-3015439220143653747?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/3015439220143653747/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=3015439220143653747&amp;isPopup=true' title='14 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/3015439220143653747'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/3015439220143653747'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/02/for-var-f-in-foes-do.html' title='for var f in foes do'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-7270572001541910194</id><published>2007-02-27T16:00:00.000+01:00</published><updated>2008-12-11T09:01:37.860+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='libros'/><category scheme='http://www.blogger.com/atom/ns#' term='Brasil'/><category scheme='http://www.blogger.com/atom/ns#' term='C++'/><title type='text'>La Cara Oculta de C++... en portugués</title><content type='html'>&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;img style="float:right; margin:1px 0 1px 8px;" src="http://2.bp.blogspot.com/_QWaXq7W8dVI/ReRKgjuBt_I/AAAAAAAAAAM/h90d_ZmgKUY/s320/brazil.jpg" border="0" alt="Brazil" /&gt;&lt;span style="font-size: 107%; font-variant: small-caps;"&gt;Hay sorpresas y sorpresas&lt;/span&gt;, y ésta es de las agradables: Thérbio, un programador de Brasil, ha contactado conmigo para obtener el permiso y traducir al portugués mi libro sobre &lt;b&gt;La Cara Oculta de C++ Builder 4&lt;/b&gt;. Por supuesto que he accedido: más bien considero un honor que el libro siga despertando interés, y he puesto todo lo necesario para facilitar la tarea.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;El proyecto se coordina desde este foro:&lt;/div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.dicasbcb.com/forum/viewforum.php?f=22"&gt;DicasBCB&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Como se trata de un libro de 1998/99, voy a proponerles también añadir parte del material sobre el API de Windows que he incluido en &lt;b&gt;Intuitive Delphi&lt;/b&gt;: objetos del núcleo, manejos de hilos, etc... aunque primero tendré que traducir el código y los ejemplos de Delphi a C++ Builder. Por supuesto, cualquier adición a la versión en portugués se reflejará en la versión en castellano.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-7270572001541910194?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/7270572001541910194/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=7270572001541910194&amp;isPopup=true' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7270572001541910194'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/7270572001541910194'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/02/la-cara-oculta-de-c-en-portugus.html' title='La Cara Oculta de C++... en portugués'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_QWaXq7W8dVI/ReRKgjuBt_I/AAAAAAAAAAM/h90d_ZmgKUY/s72-c/brazil.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-3656322674577292972</id><published>2007-02-23T12:57:00.000+01:00</published><updated>2007-02-23T13:09:33.862+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MSDN'/><title type='text'>Renovación de la suscripción MSDN</title><content type='html'>&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;span style="font-size: 107%; font-variant: small-caps;"&gt;Me tocaba renovar&lt;/span&gt; este mes la suscripción anual a la MSDN, y ya lo he hecho. Me suscribí el año pasado a Visual Studio Profesional, con MSDN Profesional. No es ni remotamente la opción más cara... pero trae todo lo que necesito (por eso lo cuento aquí). El servicio de Microsoft, además, es bueno: todos los meses, religiosamente, llega un mensajero a IntSight con un mogollón de CD's y DVD's de los que, para serle sincero, sólo llego a ver luego uno o dos.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Información que le puede interesar: la compra original me costó alrededor de 1.100 o 1.200 euros. La renovación cuesta unos 800 euros. Es mucho más barato que la cantidad que gastaba anualmente en licencias de Delphi, y lo que obtengo es un producto mucho más completo: incluye toda la suite de lenguajes: Visual C++, C#, VB.NET y JScript, aparte de todo tipo de versiones de desarrollo de SQL Server. De todos modos, le advierto que existe una versión más barata: comprar solamente Visual Studio, sin la suscripción MSDN. Los precios de primer compra están en la zona de los 800 euros, y las actualizaciones salen por unos 500 euros (cito de memoria y muy aproximadamente). De todos modos, si se puede dar el pequeño "lujo" de comprar la Team Server Edition, no se prive. Lo que echo más en falta de mi vesión Profesional es el &lt;i&gt;profiler&lt;/i&gt; que viene en las versiones superiores. Pero por suerte, .NET ofrece un API para profilers, y según los artículos que he consultdo, sería relativamente sencillo programar uno si fuese necesario.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Otro dato que le puede interesar: la renovación, al menos, se puede tramitar directamente con Microsoft España, si se quiere pagar con tarjeta. La mayoría de los distribuidores te ponen pegas si quieres pagar por esta vía, pero existe la posibilidad de comprar directamente con un comercial de Microsoft, por teléfono... que fue lo que hice.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-3656322674577292972?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/3656322674577292972/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=3656322674577292972&amp;isPopup=true' title='7 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/3656322674577292972'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/3656322674577292972'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/02/renovacin-de-la-suscripcin-msdn.html' title='Renovación de la suscripción MSDN'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-5206529971045338473</id><published>2007-02-15T13:51:00.000+01:00</published><updated>2007-02-19T12:42:03.479+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='destructor'/><title type='text'>Necesito ayuda</title><content type='html'>&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;span style="font-size: 107%; font-variant: small-caps;"&gt;¿Tiene instalado un&lt;/span&gt; Delphi.NET? Necesito que me eche una mano; no importa la versión, siempre que sea para .NET. Estoy retocando el diseño de los destructores en Freya, pero no le veo mucho sentido a la idea. Se supone que, con la ayuda de un destructor, se facilitaría la implementación de la interfaz &lt;i&gt;IDisposable&lt;/i&gt;.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;El problema está en que el patrón de implementación propuesto por Microsoft funciona a través de un método &lt;i&gt;Dispose&lt;/i&gt; auxiliar, declarado virtual y protegido, y con un parámetro de entrada de tipo booleano. Esto sirve para distinguir entre las llamadas "explícitas" a &lt;i&gt;Dispose&lt;/i&gt; (como las realizadas a través de una instrucción &lt;b&gt;using&lt;/b&gt;) de las llamadas automáticas provocadas por el colector de basura. Si no se incluye esta distinción, el destructor pierde la mayor parte de su atractivo, y puede confundir más que ayudar.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;¿Qué necesito, en concreto? Si tiene alguna versión de Delphi.NET (la 8, la 2005 o la 2006), me gustaría poder echarle un vistazo a un ensamblado pequeño compilado, preferiblemente como DLL. No me atrevo a escribir código fuente, porque no tengo forma de verificarlo sintácticamente, pero sólo necesito que incluya dos clases: una clase base y una clase derivada de la primera. Cada una de estas dos clases debe tener un destructor. Lo que haga el destructor no tiene importancia: un &lt;i&gt;WriteLine&lt;/i&gt; a la consola, por ejemplo. Eso sí, que contengan al menos una instrucción, para que el compilador no haga cosas raras con el destructor.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;O, por el contrario, si tiene claro cómo genera Delphi código para destructores en .NET, o ha escrito algún artículo, o conoce dónde hay uno, también me valdría. En este momento no tengo ningún Delphi.NET instalado: sólo mi viejo Delphi 7 "nativo".&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;... y muchas gracias por adelantado.&lt;/div&gt;&lt;hr&gt;&lt;div align="justify" style="margin-bottom: 8px; font-size: 90%;"&gt;&lt;b&gt;Actualización:&lt;/b&gt; Javier Bleda me ha dado la URL del blog de &lt;a href="http://hallvards.blogspot.com/"&gt;Hallvard Vassbotn&lt;/a&gt;, y ahí me he encontrado con el enlace a un viejo artículo de &lt;a href="http://dn.codegear.com/print/29365"&gt;Brian Long&lt;/a&gt;, donde cuenta los detalles de la técnica.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px; font-size: 90%;"&gt;A primera vista, es así como lo tengo ya implementado en Freya... pero no me convence la idea, para ser sincero: el trabajo que ahorra al programador no es significativo, y complica bastante la clase, al exigir la implementación de un tipo de interfaz, y por la necesidad de mantener el patrón en los descendientes potenciales de la clase. En el patrón oficial propuesto por Microsoft, además, se distingue entre recursos administrados y no administrados, y eso es (a primera vista) casi imposible de automatizar, excepto en circunstancias muy especiales y controladas. De todos modos, voy a pensármelo un poco antes de tomar una decisión.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-5206529971045338473?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/5206529971045338473/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=5206529971045338473&amp;isPopup=true' title='3 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/5206529971045338473'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/5206529971045338473'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/02/necesito-ayuda.html' title='Necesito ayuda'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-4201995414266209927</id><published>2007-02-15T09:31:00.000+01:00</published><updated>2007-02-15T09:46:56.820+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Freya'/><category scheme='http://www.blogger.com/atom/ns#' term='optimización'/><title type='text'>Peephole optimization</title><content type='html'>&lt;img style="display:block; margin:0px auto 10px; text-align:center;" src="http://www.marteens.com/freya/images/peephole.gif" border="0" alt="Compiler information" /&gt;&lt;br /&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;span style="font-size: 107%; font-variant: small-caps;"&gt;La imagen pertenece al&lt;/span&gt; diálogo de información sobre la compilación de Hammer, el entorno de pruebas para Freya. Como puede ver, he implementado un &lt;i&gt;peephole optimizer&lt;/i&gt;. Esto es: un optimizador que trabaja sobre el código final generado, que en este caso, es el código intermedio de .NET. El optimizador analiza la cadena de códigos ejecutables, en pequeños fragmentos, y aplica ciertas reglas de reescritura preprogramadas. Por ejemplo, un &lt;i&gt;branch to return&lt;/i&gt; es un salto incondicional que va a parar a un retorno de método. Estos saltos se eliminan, sustituyéndolos directamente por un retorno de método: así se ahorra espacio, y el tiempo que consumiría el salto.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Para ser justos, el compilador normalmente genera código de buena calidad, de modo que este paso de optimización no produce cambios espectaculares. Además, el código IL no permite muchas transformaciones, al tratarse de la simulación de una máquina de pila. En una máquina de pila, cada operación es, en cierto sentido, insensible a las operaciones que la siguen o preceden; sólo importa el contenido de la pila. De todos modos, ya he detectado unas cuantas oportunidades de mejorar el código en esta parte de la compilación.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;En cualquier caso, este módulo era necesario: el generador de código IL que ofrece &lt;i&gt;Reflection.Emit&lt;/i&gt; no es gran cosa, pues obliga a indicar explícitamente el tamaño de los códigos de saltos. Si un salto en IL se produce a una instrucción que queda a menos de 127 bytes, se puede usar un código de salto especial para que la instrucción, incluyendo el desplazamiento del salto, quepa en dos bytes. En caso contrario, ocuparía cinco bytes. El generador predefinido no ayuda para nada en la decisión del tamaño del salto. El módulo de optimización de Freya es el encargado de tomar estas decisiones, de manera automática.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-4201995414266209927?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/4201995414266209927/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=4201995414266209927&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/4201995414266209927'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/4201995414266209927'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/02/peephole-optimization.html' title='Peephole optimization'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-117107232496094107</id><published>2007-02-10T02:40:00.000+01:00</published><updated>2007-02-15T13:47:04.775+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Freya'/><title type='text'>Iteración en Freya</title><content type='html'>&lt;div style="MARGIN-BOTTOM: 8px" align="justify"&gt;&lt;span style="FONT-VARIANT: small-caps;font-size:107%;" &gt;¡Ya funcionan los&lt;/span&gt; iteradores en Freya! Había postergado la "conexión" del módulo correspondiente, pensando que iba a resultar más complicado, pero al final ha sido muy sencillo.&lt;/div&gt;&lt;pre style="MARGIN: 0px 0px 8px 24px; LINE-HEIGHT: normal"&gt;&lt;b&gt;iterator&lt;/b&gt; Stack: X;&lt;br /&gt;&lt;b&gt;begin&lt;br /&gt;    for var&lt;/b&gt; i := Count - 1 &lt;b&gt;downto&lt;/b&gt; 0 &lt;b&gt;do&lt;br /&gt;        yield&lt;/b&gt; Items[i];&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;;&lt;/pre&gt;&lt;div style="MARGIN-BOTTOM: 8px" align="justify"&gt;El truco principal consiste en recorrer el cuerpo del método iterador buscando parámetros y variables locales. Para cada uno de ellos, se crea un campo para la clase que genera el compilador internamente, y las referencias a variables y parámetros se sustituyen por referencias a los campos correspondientes. Hay que tener cuidado, porque las referencias a campos necesitan empujar antes dentro de la pila la referencia a la instancia de la clase. Un detalle elegante: las referencias a campos de la clase donde se define el iterador son muy fáciles de traducir, porque la referencia a &lt;i&gt;Self&lt;/i&gt; se considera también un parámetro del iterador, y como tal, se duplica en la clase enumerable generada por el compilador.&lt;/div&gt;&lt;div style="MARGIN-BOTTOM: 8px" align="justify"&gt;Por supuesto, quedan algunos pequeños detalles por resolver. Por ejemplo, hay que tener cuidado con los iteradores estáticos, como los que se definirían en una sección de implementación anónima, y hay que mejorar los mensajes de error del compilador cuando se escribe una instrucción &lt;b&gt;yield&lt;/b&gt; en zonas prohibidas, como la sección &lt;b&gt;finally&lt;/b&gt; de un &lt;b&gt;try&lt;/b&gt;/&lt;b&gt;finally&lt;/b&gt;.&lt;/div&gt;&lt;div style="MARGIN-BOTTOM: 8px" align="justify"&gt;¿Qué tal un ejemplo más complejo? Este es un iterador para recorrer en preorden los nodos de un árbol binario:&lt;/div&gt;&lt;pre style="MARGIN: 0px 0px 8px 24px; LINE-HEIGHT: normal"&gt;&lt;b&gt;iterator&lt;/b&gt; PreOrder: Y;&lt;br /&gt;&lt;b&gt;var&lt;/b&gt;&lt;br /&gt;    St: Stack[TreeNode];&lt;br /&gt;&lt;b&gt;begin&lt;/b&gt;&lt;br /&gt;    &lt;b&gt;if&lt;/b&gt; Root &amp;lt;&amp;gt; &lt;b&gt;nil then&lt;br /&gt;    begin&lt;/b&gt;&lt;br /&gt;        St := &lt;b&gt;new&lt;/b&gt; Stack[TreeNode];&lt;br /&gt;        St.Push(Root);&lt;br /&gt;        &lt;b&gt;repeat&lt;/b&gt;&lt;br /&gt;            &lt;b&gt;var&lt;/b&gt; t := St.Pop;&lt;br /&gt;            &lt;b&gt;if&lt;/b&gt; t.Left &amp;lt;&amp;gt; nil &lt;b&gt;then&lt;/b&gt;&lt;br /&gt;                St.Push(t.Left);&lt;br /&gt;            &lt;b&gt;if&lt;/b&gt; t.Right &amp;lt;&amp;gt; &lt;b&gt;nil&lt;/b&gt; &lt;b&gt;then&lt;/b&gt;&lt;br /&gt;                St.Push(t.Right);&lt;br /&gt;            &lt;b&gt;yield&lt;/b&gt; t.Value;&lt;br /&gt;        &lt;b&gt;until&lt;/b&gt; St.Count = 0;&lt;br /&gt;    &lt;b&gt;end&lt;/b&gt;;&lt;br /&gt;&lt;b&gt;end&lt;/b&gt;;&lt;/pre&gt;&lt;div style="MARGIN-BOTTOM: 8px" align="justify"&gt;Es interesante ver cómo se traduce el código anterior, según Reflector. El compilador crea una clase privada y anidada dentro del árbol, que implementa la interfaz &lt;i&gt;IEnumerable&lt;/i&gt;. Así es como Reflector traduce a C# el código IL generado por el compilador para el método &lt;i&gt;MoveNext&lt;/i&gt;:&lt;/div&gt;&lt;pre style="MARGIN: 0px 0px 8px 24px; LINE-HEIGHT: normal"&gt;&lt;b&gt;public sealed override bool&lt;/b&gt; MoveNext()&lt;br /&gt;{&lt;br /&gt;    &lt;b&gt;switch&lt;/b&gt; (&lt;b&gt;this&lt;/b&gt;.state$)&lt;br /&gt;    {&lt;br /&gt;        &lt;b&gt;case&lt;/b&gt; 0:&lt;br /&gt;            &lt;b&gt;if&lt;/b&gt; (&lt;b&gt;this&lt;/b&gt;.Self.Root == &lt;b&gt;null&lt;/b&gt;)&lt;br /&gt;                &lt;b&gt;goto&lt;/b&gt; Label_00D1;&lt;br /&gt;            &lt;b&gt;this&lt;/b&gt;.St = &lt;b&gt;new&lt;/b&gt; Stack&amp;lt;BinaryTree&amp;lt;Y&amp;gt;&lt;br /&gt;              .TreeNode&amp;gt;();&lt;br /&gt;            &lt;b&gt;this&lt;/b&gt;.St.Push(&lt;b&gt;this&lt;/b&gt;.Self.Root);&lt;br /&gt;            &lt;b&gt;break&lt;/b&gt;;&lt;br /&gt;        &lt;b&gt;case&lt;/b&gt; 1:&lt;br /&gt;            &lt;b&gt;this&lt;/b&gt;.state$ = -1;&lt;br /&gt;            &lt;b&gt;if&lt;/b&gt; (&lt;b&gt;this&lt;/b&gt;.St.Count != 0)&lt;br /&gt;                &lt;b&gt;break&lt;/b&gt;;&lt;br /&gt;            &lt;b&gt;goto&lt;/b&gt; Label_00D1;&lt;br /&gt;        &lt;b&gt;default&lt;/b&gt;:&lt;br /&gt;            &lt;b&gt;goto&lt;/b&gt; Label_00D1;&lt;br /&gt;    }&lt;br /&gt;    &lt;b&gt;this&lt;/b&gt;.t = &lt;b&gt;this&lt;/b&gt;.St.Pop();&lt;br /&gt;    &lt;b&gt;if&lt;/b&gt; (&lt;b&gt;this&lt;/b&gt;.t.Left != &lt;b&gt;null&lt;/b&gt;)&lt;br /&gt;        &lt;b&gt;this&lt;/b&gt;.St.Push(&lt;b&gt;this&lt;/b&gt;.t.Left);&lt;br /&gt;    &lt;b&gt;if&lt;/b&gt; (&lt;b&gt;this&lt;/b&gt;.t.Right != &lt;b&gt;null&lt;/b&gt;)&lt;br /&gt;        &lt;b&gt;this&lt;/b&gt;.St.Push(&lt;b&gt;this&lt;/b&gt;.t.Right);&lt;br /&gt;    &lt;b&gt;this&lt;/b&gt;.current$ = &lt;b&gt;this&lt;/b&gt;.t.Value;&lt;br /&gt;    &lt;b&gt;this&lt;/b&gt;.state$ = 1;&lt;br /&gt;    &lt;b&gt;return true&lt;/b&gt;;&lt;br /&gt;Label_00D1:&lt;br /&gt;    &lt;b&gt;this&lt;/b&gt;.state$ = -2;&lt;br /&gt;    &lt;b&gt;return false&lt;/b&gt;;&lt;br /&gt;}&lt;/pre&gt;&lt;div style="MARGIN-BOTTOM: 8px" align="justify"&gt;Parece más complejo de lo que realmente es... cuando se intenta traducir del formato IL a un lenguaje estructurado.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-117107232496094107?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/117107232496094107/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=117107232496094107&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/117107232496094107'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/117107232496094107'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/02/iteracin-en-freya.html' title='Iteración en Freya'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-117097004919807201</id><published>2007-02-08T22:22:00.000+01:00</published><updated>2007-02-13T12:14:18.712+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Freya'/><title type='text'>El programa más largo</title><content type='html'>&lt;div align="justify" style="margin-bottom:8px;"&gt;&lt;img src="http://www.marteens.com/xsight/images/xfreya.jpg" style="float: right; margin: 1px 0 1px 8px;" border="0" /&gt;&lt;span style="font-size: 108%; font-variant: small-caps;"&gt;¿Qué es esto?&lt;/span&gt; ¿Más noticias sobre &lt;i&gt;ray tracing&lt;/i&gt;? Sí, pero sólo en parte. Es, efectivamente, una imagen producida por un programa de &lt;i&gt;ray tracing&lt;/i&gt;, pero el programa &lt;b&gt;¡está escrito íntegramente en Freya!&lt;/b&gt;&lt;/div&gt;&lt;div align="justify" style="margin-bottom:8px;"&gt;Lo que he hecho es traducir el núcleo básico de &lt;a href="http://www.marteens.com/xsight" target="_blank"&gt;XSight RT&lt;/a&gt; a Freya, buscando errores del compilador, construcciones incómodas para el programador, traducciones ineficientes, y más cosas de este estilo. Los programas que estaba usando como pruebas del compilador no pasaban de dos o tres páginas, y quería probar con un ejemplo más ajustado a la realidad.&lt;/div&gt;&lt;div align="justify" style="margin-bottom:8px;"&gt;En realidad, el programa está empaquetado en sólo 1120 líneas de código, que he agrupado por conveniencia en un único fichero fuente. Puede examinar el fichero siguiendo este enlace:&lt;/div&gt;&lt;ul type="square"&gt;&lt;li&gt;&lt;a href="http://www.marteens.com/freya/freya_xsight.html" target="_blank"&gt;Ray tracer escrito en Freya&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div align="justify" style="margin-bottom:8px;"&gt;En la vida real, el código estaría distribuido entre varios ficheros, pero como Hammer maneja de momento sólo un documento por vez, mezclé los ficheros para simplificar la compilación. Cuando Freya esté terminado, utilizará un sistema de proyectos y soluciones muy parecido al de Visual Studio, adicional a las actuales posibilidades del compilador.&lt;/div&gt;&lt;br /&gt;&lt;div align="justify" style="margin-bottom:8px;"&gt;¿Qué contiene la prueba, y qué no contiene? La demo puede trabajar con esferas, cilindros y uniones. No he incluído soporte para operaciones de intersección y diferencia, y los materiales son, básicamente, plástico y metal. Claro, el modelo básico ya estaba suficientemente probado con C#, y todo este jaleo me ha llevado menos de un día para escribirlo, probarlo y darle forma definitiva.&lt;/div&gt;&lt;div align="justify" style="margin-bottom:8px;"&gt;¿Y qué tal de velocidad? Primero, una aclaración: la velocidad de XSight RT es similar a la de un &lt;i&gt;ray tracer&lt;/i&gt; "nativo", gracias a todo tipo de optimizaciones y a un cuidadoso diseño. En el código de ejemplo en Freya he preferido utilizar construcciones del lenguaje más elegantes que eficientes. Por ejemplo, XSight RT prácticamente renuncia al uso de operadores definidos por el programador, mientras que el ejemplo los utiliza sin reparos. A pesar de ello, los tiempos de ejecución son comparables: un ejemplo que tarda de 80 a 90 milisegundos en XSight RT se genera en Freya en un tiempo que va de 110 a 120 milisegundos.&lt;/div&gt;&lt;div align="justify" style="margin-bottom:8px;"&gt;... aunque también es cierto que el compilador de Freya está especialmente preparado para que genere mejor código que el propio compilador de C#. Ya hablaremos de optimización, en su momento...&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-117097004919807201?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/117097004919807201/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=117097004919807201&amp;isPopup=true' title='2 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/117097004919807201'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/117097004919807201'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/02/el-programa-ms-largo.html' title='El programa más largo'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-116843445164042332</id><published>2007-01-10T13:30:00.000+01:00</published><updated>2007-03-05T13:23:21.935+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ideas'/><title type='text'>Otra libra de carne</title><content type='html'>&lt;div align="right" style="font-size: 85%;font-style:italic;line-height:normal;margin-bottom: 8px;"&gt;... un momento, ¡esto suena a rock!&lt;br /&gt;Reverendo Lovejoy&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;img style="float:right; margin:1px 0 1px 8px;" src="http://www.marteens.com/adv/cossette.jpg" border="0" alt="Cossette friega los suelos para saldar su deuda con la Seguridad Social" /&gt;&lt;span style="font-style: 108%; font-variant: small-caps;"&gt;Las SS españolas, es decir&lt;/span&gt;, las seguridades sociales, que aunque son una, merecen el plural mayestático, son una fuente inagotable de sorpresa y regocijo... para quien sepa tomarse estas cosas con filosofía.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Esta vez, mis azares y aventuras me han conducido a las oficinas de las SS para solicitar una "vida laboral". Esto es, una especie de certificado de buena conducta que, a pesar de encontrarnos en pleno siglo XXI, ese monstruo llamado Estado es incapaz de transmitir vía electrónica entre dos de sus ministerios (alegrémonos de ello). De modo que me he personado en el antro que corresponde a mi &lt;i&gt;quartier&lt;/i&gt; a las 12:00 del mediodía... y me encontrado a los funcionarios con los brazos cruzados, charlando amigablemente entre ellos. ¿Una vida laboral, majete? De lunes a jueves, pero solamente entre las nueve y las once de la mañana, que es la hora en la que Saturno cruza por las antífonas del ascendente menor disminuido de Júpiter Olímpico. ¡Por el amor de Baco! ¡Santa Madre de Dionisos!&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Como soy un individuo que, muy en el fondo, aún conservo algo de fe en la especie humana, cuando consiga el dichoso certificado de sangre que me acredite como cristiano viejo, les diré que me siento como Jean Valjean. Espero que esta vez sepan quién es Jean Valjean, la pequeña Cossette y el inspector Javert. ¡Tantas veces que la han pasado por la tele!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-116843445164042332?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/116843445164042332/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=116843445164042332&amp;isPopup=true' title='9 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/116843445164042332'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/116843445164042332'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/01/otra-libra-de-carne.html' title='Otra libra de carne'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-116801608799220748</id><published>2007-01-05T17:53:00.000+01:00</published><updated>2007-02-13T12:14:35.589+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='koan'/><title type='text'>Koan de los dos hermanos</title><content type='html'>&lt;div align="justify"&gt;&lt;img src="http://www.marteens.com/adv/twins.jpg" border="0" style="float: right; margin: 1px 0 1px 8px;" alt="¿Yang y yin?" /&gt;&lt;span style="font-size: 108%; font-variant: small-caps;"&gt;Si en el Universo sólo existiesen&lt;/span&gt; dos hermanos, &lt;a href="http://www.marteens.com/koan06.htm" title="Koan de los Dos Hermanos"&gt;¿cuáles serían sus nombres?&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-116801608799220748?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/116801608799220748/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=116801608799220748&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/116801608799220748'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/116801608799220748'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/01/koan-de-los-dos-hermanos.html' title='Koan de los dos hermanos'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-116800503145403361</id><published>2007-01-05T13:57:00.000+01:00</published><updated>2007-02-13T12:15:15.601+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Freya'/><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><title type='text'>Inicializadores de colecciones</title><content type='html'>&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;img style="float:right; margin:1px 0 1px 12px;" src="http://www.marteens.com/adv/collect.gif" border="0" alt="Collection initializers: a new feature in C# 3.0" /&gt;&lt;span style="font-size: 107%; font-variant: small-caps;"&gt;Junto con los inicializadores&lt;/span&gt; de objetos, C# 3.0 introduce &lt;i&gt;inicializadores de colecciones&lt;/i&gt;, para simplificar la inicialización de objetos cuyas clases implementen la interfaz genérica &lt;i&gt;ICollection&amp;lt;T&amp;gt;&lt;/i&gt;.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Suponga que estamos trabajando con C# 2.0, y que queremos crear una lista genérica de enteros y añadirle unos cuantos elementos iniciales:&lt;/div&gt;&lt;pre style="margin: 0 0 8px 24px; line-height: normal;"&gt;List&amp;lt;&lt;b&gt;int&lt;/b&gt;&amp;gt; lista =&lt;br /&gt;    &lt;b&gt;new&lt;/b&gt; List&amp;lt;&lt;b&gt;int&lt;/b&gt;&amp;gt;(&lt;b&gt;new int&lt;/b&gt;[] { 1, 2, 3, 4 });&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;El ejemplo anterior utiliza uno de los constructores de la clase &lt;i&gt;List&lt;/i&gt;, que recibe un parámetro de tipo &lt;i&gt;IEnumerable&lt;/i&gt;, en su versión genérica. El CLR considera que todo vector implementa dicha interfaz, por lo que el compilador genera instrucciones para crear el vector para luego pasarlo al constructor de &lt;i&gt;List&lt;/i&gt;.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;¿Se da cuenta de lo ineficiente que es esta técnica? Observe el código aproximado que debe generar el compilador, con sintaxis C# para no hacerlo ilegible:&lt;/div&gt;&lt;pre style="margin: 0 0 8px 24px; line-height: normal;"&gt;&lt;b&gt;int&lt;/b&gt;[] temp = &lt;b&gt;new int&lt;/b&gt;[4];&lt;br /&gt;temp[0] = 1;&lt;br /&gt;temp[1] = 2;&lt;br /&gt;temp[2] = 3;&lt;br /&gt;temp[3] = 4;&lt;br /&gt;List&amp;lt;&lt;b&gt;int&lt;/b&gt;&amp;gt; lista = &lt;b&gt;new&lt;/b&gt; List&amp;lt;&lt;b&gt;int&lt;/b&gt;&amp;gt;(temp);&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Pero esto es sólo lo que ocurre a la vista de todos. Recuerde que el parámetro recibido por el constructor es una interfaz &lt;i&gt;IEnumerable&lt;/i&gt;. El constructor debe ejecutar el método &lt;i&gt;GetEnumerator&lt;/i&gt; de la referencia recibida, y llamar al método &lt;i&gt;MoveNext&lt;/i&gt; repetidas veces sobre el resultado de la llamada.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Bienvenidos a C# 3.0. Ahora podemos usar esta sintaxis:&lt;/div&gt;&lt;pre style="margin: 0 0 8px 24px; line-height: normal;"&gt;List&amp;lt;&lt;b&gt;int&lt;/b&gt;&amp;gt; lista =&lt;br /&gt;    &lt;b&gt;new&lt;/b&gt; List&amp;lt;&lt;b&gt;int&lt;/b&gt;&amp;gt;(){ 1, 2, 3, 4 };&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Los cambios son sutiles, pero importantes. Ahora utilizamos el constructor sin parámetros de &lt;i&gt;List&lt;/i&gt;, aunque tenemos la libertad de usar el constructor que mejor nos parezca, pues la lista de elementos iniciales no se pasa como parámetro del constructor. Por el contrario, la lista se yuxtapone tras el paréntesis de cierre de la lista de parámetros. Aunque parece un vector literal, no lo es: no hay indicación del tipo de los elementos... porque exigiremos que sean compatibles con el tipo de elemento de la lista. La traducción es la siguiente:&lt;/div&gt;&lt;pre style="margin: 0 0 8px 24px; line-height: normal;"&gt;List&amp;lt;&lt;b&gt;int&lt;/b&gt;&amp;gt; lista = &lt;b&gt;new&lt;/b&gt; List&amp;lt;&lt;b&gt;int&lt;/b&gt;&amp;gt;(temp);&lt;br /&gt;lista.Add(1);&lt;br /&gt;lista.Add(2);&lt;br /&gt;lista.Add(3);&lt;br /&gt;lista.Add(4);&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Ya no tenemos que crear e inicializar un vector de usar y tirar. Ya no hay un bucle dentro del constructor. Ya no se crea una instancia temporal de &lt;i&gt;IEnumerator&lt;/i&gt; para el bucle del constructor. De manera que no sólo ahorramos tiempo, de manera directa, sino que también ahorramos memoria, y aliviamos la carga del &lt;i&gt;garbage collector&lt;/i&gt;.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Sólo nos queda un detalle por aclarar. Las llamadas al método &lt;i&gt;Add&lt;/i&gt; tienen en realidad este aspecto:&lt;/div&gt;&lt;pre style="margin: 0 0 8px 24px;"&gt;((ICollection&amp;lt;&lt;b&gt;int&lt;/b&gt;&amp;gt;)lista).Add(1);&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Pero esto no significa una carga adicional, porque la conversión anterior no genera código adicional... al menos en lenguaje intermedio. Tengo que comprobar todavía lo que ocurre cuando se traduce a código nativo.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Como imaginará, cuento todo esto porque acabo de añadir a Freya estos inicializadores de colecciones. Eso sí, la sintaxis provisional es "fea":&lt;/div&gt;&lt;pre style="margin: 0 0 8px 24px;"&gt;List[Integer] := &lt;b&gt;new&lt;/b&gt; List[Integer]![1,2,3,4];&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;No podemos yuxtaponer sin más el inicializador a la expresión &lt;b&gt;new&lt;/b&gt;, porque Freya permite omitir los paréntesis cuando no hay parámetros, y porque usamos los corchetes para los parámetros de tipos genéricos. No podemos usar ninguno de los operadores permitidos en expresiones, porque introduciríamos ambigüedad en el lenguaje. He probado el uso de la asignación de Pascal, y aunque no causa problemas, el efecto estético es horroroso. Me he quedado con el signo de admiración porque me ha parecido el menor de los males.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-116800503145403361?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/116800503145403361/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=116800503145403361&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/116800503145403361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/116800503145403361'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/01/inicializadores-de-colecciones.html' title='Inicializadores de colecciones'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-116783078859838534</id><published>2007-01-03T14:09:00.000+01:00</published><updated>2007-03-05T13:24:16.384+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ideas'/><title type='text'>A Pound of Flesh</title><content type='html'>&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;img src="http://www.marteens.com/adv/justice.jpg" border="0" style="float: right; margin: 2px 0 0 12px;" alt="... and Justice for All"&gt;&lt;span style="font-size: 107%; font-variant: small-caps;"&gt;Acabo de poner en práctica&lt;/span&gt; un experimento que me ha revelado un hecho sorprendente: ¡en la Seguridad Social (SS en lo sucesivo) no conocen a Shakespeare! No es que no sepan qué es El Mercader de Venecia, desgraciada obra antisemita que desmerece el genio del Bardo de Avon, o incluso que no conozcan a Jeremy Irons y Al Pacino: el propio Shakespeare les suena a nombre de inmigrante chino.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Y no se trata de un experimento efectuado sobre un único y pobre desgraciado elegido al azar por un experimentador chiflado que se cree Dios: le he dicho a la funcionaria que me atendió que quería pagar mi libra de carne y cuando, tras torcer el gesto y regañarme, ha confesado desconocer de qué iba la historia, me he tomado el atrevimiento (y la molestia) de ir buró por buró (sitio donde se enquistan los burócratas de la SS española) preguntando a sus nueve compañeros si tenían alguna idea de lo que significaba &lt;i&gt;una libra de carne&lt;/i&gt;. Unánime negativa. Incluso he preguntado si lo negaban por fastidiarme. Desconcierto y sorpresa.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Lo peor de todo, o lo mejor, según como se mire, es lo que me ocurrió al despedirme: la personita, ofendida en lo más profundo de su alma logseana, me espetó:&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px; margin-left: 32px;"&gt;- ¡Nadie que venga con una Biblia en la mano tiene derecho a echarme un sermón!&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 12px;"&gt;Abrí los ojos como platos, hasta que comprendí a qué se refería. Entonces levante la mano con la que sostenía el libro, y le enseñé la portada de mi ejemplar encuadernado en piel de las &lt;i&gt;"Lectures on Quantum Mechanics"&lt;/i&gt;, de Paul Adrien Maurice Dirac, que yo, ateo budista, había llevado para aliviar mi espera en la larga cola de suplicantes.&lt;/div&gt;&lt;div align="justify" style="font-size: 90%; font-style: italic; margin: 0 12px 12px 12px;"&gt;Post scriptum: El incidente, en sí, es más grotesco que terrible. Tampoco pretendo que se obligue a leer a Shakespeare en la escuela pública, ni a Dirac, ni siquiera la Biblia. Lo terrible es que gente así se atribuya constantemente el poder de decidir por todos nosotros.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-116783078859838534?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/116783078859838534/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=116783078859838534&amp;isPopup=true' title='13 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/116783078859838534'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/116783078859838534'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2007/01/pound-of-flesh.html' title='A Pound of Flesh'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-116687631154181935</id><published>2006-12-23T13:13:00.000+01:00</published><updated>2006-12-23T13:20:06.630+01:00</updated><title type='text'>¡Feliz Navidad!</title><content type='html'>&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;span style="font-size: 107%; font-variant: small-caps;"&gt;... para ser sincero&lt;/span&gt;, no soy muy fan de las Navidades. Pero ahora que es políticamente incorrecto hablar de Navidades en según qué ministerios, sería una pena desaprovechar una oportunidad para dar un poco por saco.&lt;/div&gt;&lt;div&gt;Lo dicho: Feliz Navidad, Bon Nadal, Zorionak, Merry Christmas, Joyeux Noël, etc, etc, y aunque un poco tarde, feliz Hanukkah.&lt;/div&gt;&lt;div&gt;&lt;i&gt;(he pasado del Kwanza, como podéis ver...)&lt;/i&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-116687631154181935?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/116687631154181935/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=116687631154181935&amp;isPopup=true' title='7 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/116687631154181935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/116687631154181935'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2006/12/feliz-navidad.html' title='¡Feliz Navidad!'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-22471446.post-116671574896680462</id><published>2006-12-21T16:37:00.000+01:00</published><updated>2007-02-13T12:14:53.147+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Freya'/><title type='text'>Métodos anónimos</title><content type='html'>&lt;div align="justify" style="margin-bottom: 8px;"&gt;&lt;img src="http://www.marteens.com/images/braces.jpg" border="0" style="float: left; margin: 1px 8px 0 0;" /&gt;&lt;span style="font-size: 107%; font-variant: small-caps;"&gt;Voy a ocuparme un poco&lt;/span&gt; del compilador de Freya, ahora que baja la carga de trabajo por fin de año. Quiero terminar de implementar el soporte de métodos genéricos, introducir la inferencia de tipos para argumentos genéricos en llamadas a métodos genéricos, y probablemente de los primeros pasos para implementar métodos anónimos.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Con estos últimos, voy a saltarme una versión, y los voy a implementar desde el principio como las expresiones lambda de C# 3.0:&lt;/div&gt;&lt;pre style="margin: 0 0 8px 24px;"&gt;&lt;b&gt;var&lt;/b&gt; L: List[Integer] := [1, 2, 3, 4];&lt;br /&gt;&lt;b&gt;if&lt;/b&gt; L.Exists(&lt;font color="red"&gt;x =&gt; x &lt;b&gt;mod&lt;/b&gt; 2 = 0&lt;/font&gt;) &lt;b&gt;then&lt;/b&gt;&lt;br /&gt;    Console.WriteLine('Pares en la lista');&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;La sintaxis del ejemplo (la porción resaltada en rojo) es la del caso más simple: un método anónimo que devuelve un valor calculado con una expresión, que recibe un solo parámetro, y que el tipo de dicho es parámetro es inferible a partir del contexto.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;El problema consiste en qué hacer en el caso más general: en C#, gracias a su sintaxis espartana, la versión completa de un método anónimo es aceptable. En un lenguaje pascaloide (o "algoloide"), es otra cosa. Esto sería una expresión en C#:&lt;/div&gt;&lt;pre style="margin: 0 0 8px 24px;"&gt;&lt;b&gt;delegate&lt;/b&gt;(&lt;b&gt;int&lt;/b&gt; x) { &lt;b&gt;return&lt;/b&gt; x % 2 == 0; }&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Y esto sería el equivalente literal en Freya:&lt;/div&gt;&lt;pre style="margin: 0 0 8px 24px;"&gt;&lt;b&gt;method&lt;/b&gt;(x: integer) &lt;b&gt;begin&lt;/b&gt; result := x &lt;b&gt;mod&lt;/b&gt; 2 = 0 &lt;b&gt;end&lt;/b&gt;&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Si no ve dónde está el problema, recuerde que estas "expresiones" pueden usarse ahora como parámetros en llamadas a métodos.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;En realidad, hay otro problema por el que le estoy dando tantas vueltas a la sintaxis. Me gustaría poder plasmar la idea de &lt;i&gt;método anónimo = extensión de estructuras de control&lt;/i&gt;. Las listas genéricas en .NET tienen un método &lt;i&gt;ForEach&lt;/i&gt;, un iterador cerrado, que acepta un parámetro de tipo delegado:&lt;/div&gt;&lt;pre style="margin: 0 0 8px 24px;"&gt;lista.ForEach(x =&gt; Console.WriteLine(x));&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;En este caso, C# ha considerado que la llamada a &lt;i&gt;WriteLine&lt;/i&gt; se puede considerar, en el sentido más laxo, una función que no devuelve nada. Por lo tanto, permite eliminar las llaves que de otro modo deberían encerrar el bloque de instrucciones.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;A mí me gustaría que Freya pudiera hacer esto (olvide por un momento el uso incorrecto de las palabras reservadas):&lt;/div&gt;&lt;pre style="margin: 0 0 8px 24px;"&gt;&lt;b&gt;with&lt;/b&gt; x &lt;b&gt;apply&lt;/b&gt; lista.ForEach &lt;b&gt;do&lt;/b&gt; Console.WriteLine(x);&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;Esto es: me gustaría disponer de una instrucción de control "comodín" que pudiese simplificar el uso de métodos anónimos como parámetros de métodos... siempre que se cumpliesen algunas condiciones, como que el método sólo admitiese un parámetro de tipo delegado. Claro: esto no tendría sentido con una llamada al método &lt;i&gt;Exists&lt;/i&gt; que mostré en el primer ejemplo, pues este método debe devolver un valor.&lt;/div&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;¿Tendría sentido una instrucción como la que imagino? ¿Tendría aplicación más allá de su evidente utilidad con iteradores cerrados? Teniendo en cuenta que ya Freya cuenta con un mecanismo útil y eficiente de iteradores abiertos, si sólo valiese para iteradores cerrados, no creo que mereciese la pena: es incluso probable que fuese mejor adaptar la sintaxis del &lt;b&gt;foreach&lt;/b&gt; de C# para estos casos. Por último, ¿podría utilizarse una instrucción de este tipo para simplificar la conexión de manejadores anónimos a eventos? Esto es C# 2.0:&lt;/div&gt;&lt;pre style="margin: 0 0 8px 24px;"&gt;button1.Click += &lt;b&gt;delegate&lt;/b&gt; { Console.WriteLine("Click"); };&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;¿No sería preferible algo así en Freya?&lt;/div&gt;&lt;pre style="margin: 0 0 8px 24px;"&gt;&lt;b&gt;when&lt;/b&gt; button1.Click &lt;b&gt;do&lt;/b&gt; Console.WriteLine('Click');&lt;/pre&gt;&lt;div align="justify" style="margin-bottom: 8px;"&gt;¡Ojo! No estoy convencido de que sea buena idea: sólo pregunto. No me gustaría añadir dos instrucciones diferentes para estos dos casos... pero tampoco estoy seguro de poder unificarlos.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22471446-116671574896680462?l=commanet.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://commanet.blogspot.com/feeds/116671574896680462/comments/default' title='Enviar comentarios'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=22471446&amp;postID=116671574896680462&amp;isPopup=true' title='0 comentarios'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/116671574896680462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/22471446/posts/default/116671574896680462'/><link rel='alternate' type='text/html' href='http://commanet.blogspot.com/2006/12/mtodos-annimos.html' title='Métodos anónimos'/><author><name>Ian Marteens</name><uri>http://www.blogger.com/profile/01802552330071620377</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://www.marteens.com/ianm.gif'/></author><thr:total>0</thr:total></entry></feed>
