<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://msmvps.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>Angel "Java" Lopez : Proyectos de Código Abierto, AjSharp</title><link>http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_F300_digo+Abierto/AjSharp/default.aspx</link><description>Tags: Proyectos de Código Abierto, AjSharp</description><dc:language>en</dc:language><generator>CommunityServer 2008.5 SP2 (Build: 40407.4157)</generator><item><title>Servidor y Cliente en AjSharp Distribuido</title><link>http://msmvps.com/blogs/lopez/archive/2010/06/14/servidor-y-cliente-en-ajsharp-distribuido.aspx</link><pubDate>Mon, 14 Jun 2010 10:09:49 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1771977</guid><dc:creator>lopez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1771977</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/06/14/servidor-y-cliente-en-ajsharp-distribuido.aspx#comments</comments><description>&lt;p&gt;En mis anteriores posts:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/05/23/distributed_2D00_ajsharp_2D00_a_2D00_roadmap.aspx" target="_blank"&gt;AjSharp Distribuido: un Roadmap&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://ajlopez.wordpress.com/2010/05/22/distributed-ajsharp-a-roadmap/" target="_blank"&gt;Distributed AjSharp: a Roadmap&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/05/18/distributed_2D00_ajsharp_2D00_first_2D00_steps.aspx" target="_blank"&gt;AjSharp Distribuido: Primeros pasos&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://ajlopez.wordpress.com/2010/05/17/distributed-ajsharp-first-steps/" target="_blank"&gt;Distributed AjSharp: First Steps&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;escribí una breve descripción de lo que quiero para un AjSharp distribuido (mi intérprete de código abierto), y mostré unas pocas “screenshots” de programas en ejecución distribuida. Examinemos y corramos un ejemplo simple pero concreto.&lt;/p&gt;  &lt;p&gt;Podemos lanzar el intérprete interactivo con el comando de línea&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;AjSharp.Console&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;Podemos agregar una lista de archivos .ajs con código fuente, para ser ejecutados inmediatamente:&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;AjSharp.Console program1.ajs program2.ajs&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;La idea, en este primer ejemplo distribuido, es lanzar dos instancias del intérprete, y en una, lanzar un servidor, y en otra lanzar un programa cliente que se comunique con el servidor. Ni bien tenga la conexión con éste, el programa cliente envía comandos a ejecutar en el servidor.&lt;/p&gt;  &lt;p&gt;Primero, el código del programa servidor:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0px;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;server = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; RemotingHostServer(10000, &amp;quot;&lt;span style="color:#8b0000;"&gt;Server&lt;/span&gt;&amp;quot;);
PrintLine(&amp;quot;&lt;span style="color:#8b0000;"&gt;Server started&lt;/span&gt;&amp;quot;);
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;La clase interna &lt;strong&gt;RemotingHostServer&lt;/strong&gt; lanza un servidor de remoting. El primer parámetro es la puerta TCP, y el segundo parámetro el nombre lógico del servidor. Se pueden lanzar varios servidores en la misma instancia del intérprete. En nuestro ejemplo, sólo necesitaremos uno.&lt;/p&gt;

&lt;p&gt;Ahora, el código para el nodo cliente:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0px;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;remote = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; RemotingHostClient(&amp;quot;&lt;span style="color:#8b0000;"&gt;localhost&lt;/span&gt;&amp;quot;, 10000, &amp;quot;&lt;span style="color:#8b0000;"&gt;Server&lt;/span&gt;&amp;quot;);
at remote PrintLine(&amp;quot;&lt;span style="color:#8b0000;"&gt;New Node&lt;/span&gt;&amp;quot;);
nodeid = System.Guid.NewGuid().ToString();
&lt;span style="color:#008000;"&gt;// evaluate a subroutine at server&lt;/span&gt;
at remote 
	sub(id)
	{
		&lt;span style="color:#0000ff;"&gt;for&lt;/span&gt; (k=1; k&amp;lt;=10; k++)
			PrintLine(&amp;quot;&lt;span style="color:#8b0000;"&gt;Hello, server, from node &lt;/span&gt;&amp;quot; + id);
	}
	with (nodeid); &lt;span style="color:#008000;"&gt;// local parameter going to server&lt;/span&gt;
	
exit;&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;El objeto &lt;strong&gt;RemotingHostClient&lt;/strong&gt; conecta con un servidor. Su constructor toma el nombre de la máquina destino, el puerto de TCP a usar, y el nombre lógico del servidor. Usando esos parámetros, internamente arma una dirección de remoting, usando un canal TCP.&lt;/p&gt;

&lt;p&gt;Ahora que tenemos una conexión, con el comando &lt;strong&gt;at&lt;/strong&gt; ejecutamos un comando en el servidor remoto. La sintaxis es:&lt;/p&gt;

&lt;p&gt;&lt;font face="Consolas"&gt;at &amp;lt;server&amp;gt; &amp;lt;cmd&amp;gt;&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;Entonces&lt;/p&gt;

&lt;p&gt;&lt;font face="Consolas"&gt;at remote PrintLine(“New Node”);&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;imprime un mensaje en la consola del servidor, no en el cliente. Otra variante es:&lt;/p&gt;

&lt;p&gt;&lt;font face="Consolas"&gt;at &amp;lt;server&amp;gt; &amp;lt;functionorsub&amp;gt; with (&amp;lt;parameters&amp;gt;);&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;que evalúa una función o subrutina en el servidor, pasando una lista de parámetros cuyos valores se evalúan en el ambiente del cliente.&lt;/p&gt;

&lt;p&gt;Preparé un ejemplo empaquedo, con el AjSharp ya compilado, que se puede bajar de mi Skydrive: &lt;a href="http://cid-9f903f3d6db0c176.office.live.com/self.aspx/Examples/AjSharp/AjSharpDistributed01.zip" target="_blank"&gt;AjSharpDistributed01.zip&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;En una consola del sistema operativo, ejecutar&lt;/p&gt;

&lt;p&gt;&lt;font face="Consolas"&gt;StartServer.cmd&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;Este comando arranca una nueva consola, que ejecuta el código Server.ajs.&lt;/p&gt;

&lt;p&gt;Para ejecutar un nodo cliente&lt;/p&gt;

&lt;p&gt;&lt;font face="Consolas"&gt;RunNode.cmd&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;Este es la típica salida en el código del servidor, luego de lanzar dos nodos:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/ajsharp20.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;Como siempre, pueden bajar el código completo desde:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://go2.wordpress.com/?id=725X1342&amp;amp;site=ajlopez.wordpress.com&amp;amp;url=http%3A%2F%2Fcode.google.com%2Fp%2Fajcodekatas%2Fsource%2Fbrowse%2F&amp;amp;sref=http%3A%2F%2Fajlopez.wordpress.com%2F2010%2F03%2F15%2Fscripting-watin-using-ajsharp%2F"&gt;http://code.google.com/p/ajcodekatas/source/browse/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;en el directorio trunk/AjLanguage. Estoy escribiendo más ejemplos distribuidos: ejecutar un archivo de código fuente local en el servidor, ejecutar código en un servidor cuando un nuevo servidor informa su existencia, agentes distribuidos, etc…&lt;/p&gt;

&lt;p&gt;Nos leemos!&lt;/p&gt;

&lt;p&gt;Angel “Java” Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1771977" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx">AjSharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_F300_digo+Abierto/default.aspx">Proyectos de Código Abierto</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Aplicaciones+Distribuidas/default.aspx">Aplicaciones Distribuidas</category></item><item><title>Transacciones en memoria en AjSharp usando References</title><link>http://msmvps.com/blogs/lopez/archive/2010/06/08/memory_2D00_transactions_2D00_in_2D00_ajsharp_2D00_using_2D00_references.aspx</link><pubDate>Tue, 08 Jun 2010 09:19:28 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1771607</guid><dc:creator>lopez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1771607</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/06/08/memory_2D00_transactions_2D00_in_2D00_ajsharp_2D00_using_2D00_references.aspx#comments</comments><description>&lt;p&gt;El año pasado me encontré con &lt;a href="http://clojure.org/" target="_blank"&gt;Clojure&lt;/a&gt;, un dialecto de Lisp que compila a Java. Estuve codificando AjSharpure (ver &lt;a href="http://ajlopez.wordpress.com/2010/01/04/ajlisp-family-implementing-lisp-interpreters-in-c/" target="_blank"&gt;AjLisp Family: Implementing Lisp Interpreters in C#&lt;/a&gt;)(&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/01/05/ajlisp_2D00_family_2D00_implementing_2D00_lisp_2D00_interpreters_2D00_in_2D00_c.aspx" target="_blank"&gt;La familia AjLisp, implementando intérpretes Lisp en C#&lt;/a&gt;), un intérprete tipo Clojure (no un compilador) en .NET (si necesitan una más completa implementación en .NET, hay un ClojureCLR, compilado usando DLR, Dynamic Language Runtime).&lt;/p&gt;  &lt;p&gt;Clojure tiene varias características interesantes, especialmente las estructuras persistentes (persistencia acá no es grabar en una base de datos, sino tener listas, diccionarios, árboles “inmutables”; cuando uno agregar algo a una lista, la lista original queda igual, y se construye una nueva lista…), concurrencia, agentes, y más. Una de sus características es su soporte de STM, Software Transactional Memory. Más sobre estos temas en links al final de este post. De acuerdo a:&lt;/p&gt;  &lt;p&gt;&lt;a title="http://en.wikipedia.org/wiki/Software_transactional_memory" href="http://en.wikipedia.org/wiki/Software_transactional_memory"&gt;http://en.wikipedia.org/wiki/Software_transactional_memory&lt;/a&gt;&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;In &lt;a href="http://en.wikipedia.org/wiki/Computer_science"&gt;computer science&lt;/a&gt;, &lt;b&gt;software transactional memory&lt;/b&gt; (STM) is a &lt;a href="http://en.wikipedia.org/wiki/Concurrency_control"&gt;concurrency control&lt;/a&gt; mechanism analogous to &lt;a href="http://en.wikipedia.org/wiki/Database_transaction"&gt;database transactions&lt;/a&gt; for controlling access to &lt;a href="http://en.wikipedia.org/wiki/Shared_memory"&gt;shared memory&lt;/a&gt; in &lt;a href="http://en.wikipedia.org/wiki/Concurrent_computing"&gt;concurrent computing&lt;/a&gt;. It is an alternative to &lt;a href="http://en.wikipedia.org/wiki/Lock_%28computer_science%29"&gt;lock-based synchronization&lt;/a&gt;. A transaction in this context is a piece of code that executes a series of reads and writes to shared memory. These reads and writes logically occur at a single instant in time; intermediate states are not visible to other (successful) transactions.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Hace unas semanas, leí:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://pramode.net/clojure/2010/05/23/clojure-concurrency-part-4/" target="_blank"&gt;Clojure concurrency Part 4&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Ese artículo describe la conducta de “ref”, “dosync” y operaciones relacionadas sobre “ref”. Quería experimentar con esas características, pero en mi intéprete &lt;a href="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx" target="_blank"&gt;AjSharp&lt;/a&gt;. Así, que escribí una clase &lt;strong&gt;Reference&lt;/strong&gt;, y agregué soporte de transacciones al lenguaje.&lt;/p&gt;  &lt;p&gt;Ahora, puedo escribir:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;reference = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Reference();
reference &amp;lt;- 1;
result = @reference;&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;La clase &lt;strong&gt;Reference&lt;/strong&gt; es una “built&amp;#39;-in”. En AjLanguage/AjSharp el operador &amp;lt;- es equivalente a &lt;strong&gt;ref.SetValue(newvalue)&lt;/strong&gt;. Ahora, agregué el operador @ para obtener el valor, y es equivalente a &lt;strong&gt;ref.GetValue()&lt;/strong&gt; (incidentalmente, &lt;strong&gt;GetValue&lt;/strong&gt; and &lt;strong&gt;SetValue&lt;/strong&gt; son los métodos de las interfaces de &lt;strong&gt;Channels&lt;/strong&gt; y &lt;strong&gt;Futures&lt;/strong&gt;, ver:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://ajlopez.wordpress.com/2010/01/25/ajsharp-implementing-futures/" target="_blank"&gt;AjSharp: Implementing Futures&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/01/28/ajsharp_2D00_implementing_2D00_futures.aspx" target="_blank"&gt;AjSharp: Implementando Futures&lt;/a&gt;

  &lt;br /&gt;&lt;a href="http://ajlopez.wordpress.com/2009/12/28/channels-and-goroutines-in-ajsharp-part-1/" target="_blank"&gt;Channels and Go Routines in AjSharp (Part 1)&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2009/12/29/channels_2D00_and_2D00_goroutines_2D00_in_2D00_ajsharp_2D00_part_2D00_1.aspx" target="_blank"&gt;Canales y Go Routines en AjSharp (Parte 1)&lt;/a&gt;

  &lt;br /&gt;&lt;a href="http://ajlopez.wordpress.com/2009/12/30/channels-and-goroutines-in-ajsharp-part-2/" target="_blank"&gt;Channels and Go Routines in AjSharp (Part 2)&lt;/a&gt;

  &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2009/12/31/channels_2D00_and_2D00_goroutines_2D00_in_2D00_ajsharp_2D00_part_2D00_2.aspx" target="_blank"&gt;Canales y Go Routines en AjSharp (Parte 2)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En esos posts, todavía escribía &lt;strong&gt;&amp;lt;-channel&lt;/strong&gt; o &lt;strong&gt;&amp;lt;-future&lt;/strong&gt; para OBTENER el valor desde un channel o future; ahora, estoy decidiendo poner como obsoleta esa notación, en favor de &lt;strong&gt;@channel&lt;/strong&gt;, &lt;strong&gt;@future&lt;/strong&gt;, que me parece más clara).&lt;/p&gt;

&lt;p&gt;Decidí hacer que las operaciones de get/set de valor sean explícitas, usando esos operadores, en vez de hacerlas transparentes. Eso mismo había decidido para manipular canales y valores futuros.&lt;/p&gt;

&lt;p&gt;Pero, ¿cómo se usa una referencia? Bien, empieza a cobrar sentido con la nueva palabra clave &lt;strong&gt;transaction&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;channel1 = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Channel();
end1 = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Channel();
end2 = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Channel();
reference1 = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Reference();
reference2 = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Reference();
reference1 &amp;lt;- 1;
reference2 &amp;lt;- 2;
go transaction 
{ 
  reference1 &amp;lt;- @channel1; 
  result2original = @reference2; 
  end1 &amp;lt;- @reference1; 
}
go transaction 
{ 
  channel1 &amp;lt;- @reference2; 
  reference2 &amp;lt;- @reference2 + 1; 
  result1original = @reference1; 
  end2 &amp;lt;- @reference2; 
}
result1 = @end1; &lt;span style="color:#008000;"&gt;// 2&lt;/span&gt;
result2 = @end2; &lt;span style="color:#008000;"&gt;// 3&lt;/span&gt;
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Las dos transacciones son lanzadas con el comando go (ver los posts citados más arriba para ver go routines en AjSharp). La primera transacción espera a recibir un valor de la segunda, usando un canal que está en la variable &lt;strong&gt;channel1&lt;/strong&gt;. Los valores en &lt;strong&gt;reference1&lt;/strong&gt;, &lt;strong&gt;reference2&lt;/strong&gt; en la primer transacción son los originales, aunque al mismo tiempo están siendo cambiados en la segunda. Esto es, una transacción ve un “snapshot” de los valores almacenados en referencias, tomados al comienzo de su vida. Un cambio en un valor de una referencia durante una transacción, es confirmada al final de la transacción, y entonces, se vuelve visible al resto de la transacción. Pero las transacciones que aún se encuentren en ejecución, ven el valor del “snapshot”. Si una transacción altera el valor de una referencia que ha sido alterado por otra transacción concurrente, se lanza una excepción.&lt;/p&gt;

&lt;p&gt;Mi implementación es sencilla e ingenua. Podría mejorarla. Pero por ahora, los tests dan verde, y es lo bastante buena para mis experimentos. Internamente, cada referencia tiene un valor actual visible, un posible valor actualizado por una transacción en ejecución (no se admiten DOS valores actualizados), una lista de valores de “snapshots”, para alimentar a transacciones que aún estan en ejecución. Una instancia de &lt;strong&gt;Machine, &lt;/strong&gt;asociada al thread en ejecución mantiene una lista de referencias con “snapshots”, y una lista de transacciones en ejecución.&lt;/p&gt;

&lt;p&gt;Mis enlaces:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://delicious.com/ajlopez/clojure"&gt;http://delicious.com/ajlopez/clojure&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://delicious.com/ajlopez/clojure+concurrency"&gt;http://delicious.com/ajlopez/clojure+concurrency&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://delicious.com/ajlopez/clojure+tutorial"&gt;http://delicious.com/ajlopez/clojure+tutorial&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://delicious.com/ajlopez/stm"&gt;http://delicious.com/ajlopez/stm&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://delicious.com/ajlopez/clojure+stm"&gt;http://delicious.com/ajlopez/clojure+stm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como siempre, pueden bajarse el código en:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://go2.wordpress.com/?id=725X1342&amp;amp;site=ajlopez.wordpress.com&amp;amp;url=http%3A%2F%2Fcode.google.com%2Fp%2Fajcodekatas%2Fsource%2Fbrowse%2F&amp;amp;sref=http%3A%2F%2Fajlopez.wordpress.com%2F2010%2F03%2F15%2Fscripting-watin-using-ajsharp%2F"&gt;http://code.google.com/p/ajcodekatas/source/browse/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;en el directorio trunk/AjLanguage.&lt;/p&gt;

&lt;p&gt;Nos leemos!&lt;/p&gt;

&lt;p&gt;Angel “Java” Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1771607" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx">AjSharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_F300_digo+Abierto/default.aspx">Proyectos de Código Abierto</category></item><item><title>AjSharp Distribuido: un roadmap</title><link>http://msmvps.com/blogs/lopez/archive/2010/05/23/distributed_2D00_ajsharp_2D00_a_2D00_roadmap.aspx</link><pubDate>Sun, 23 May 2010 12:15:21 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1768445</guid><dc:creator>lopez</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1768445</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/05/23/distributed_2D00_ajsharp_2D00_a_2D00_roadmap.aspx#comments</comments><description>&lt;p&gt;El pasado fin de semana, estuve agregando características a mi intérprete de código abierto &lt;a href="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx" target="_blank"&gt;AjSharp&lt;/a&gt;, para que comenzara a soportar ejecución distribuida. Escribí sobre el tema en:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ajlopez.wordpress.com/2010/05/17/distributed-ajsharp-first-steps/" target="_blank"&gt;Distributed AjSharp: First Steps&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/05/18/distributed_2D00_ajsharp_2D00_first_2D00_steps.aspx" target="_blank"&gt;AjSharp Distribuido: Primeros Pasos&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;(más post en español &lt;a title="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx" href="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx"&gt;http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx&lt;/a&gt;)    &lt;br /&gt;(más post en inglés/Anglish (Angel´s English :-) &lt;a title="http://en.wordpress.com/tag/ajsharp/" href="http://en.wordpress.com/tag/ajsharp/"&gt;http://en.wordpress.com/tag/ajsharp/&lt;/a&gt;) &lt;/p&gt;  &lt;p&gt;En esta semana pasada, escribí más código para soportar la ejecución distribuida de una aplicación AjSharp. Es un “work in progress”. De alguna manera, es la continuación de mi trabajo con aplicaciones distribuidas, que comenzó luego de mi trabajo con Fabriq, antes un poco con AjServer,&amp;#160; luego con AjMessages, y así. La escritura de un intérprete propio permite extender el lenguaje para soportar características que tal vez se complicarían de implementar en lenguajes tipados, compilados.&lt;/p&gt;  &lt;p&gt;En este post, quiero escribir una lista de features que me gustaría agregar (algunas ya están agregadas en el código de trunk, pero tengo que revisarlas, probarlas mejor y escribir posts sobre cómo usarlas y cómo funcionan). Antes, algunas aclaraciones de nomenclatura:&lt;/p&gt;  &lt;p&gt;Machine.Current es un objeto base que mantiene el Environment global (Machine.Current.Environment), que contiene los nombres/valores de las variables globales, las definiciones de las clases, funciones globales, etc.. Host es un objeto que expone una Machine para que sea accedida desde otros Host. Machine es un concepto básico de AjSharp/AjLanguage. Host es lo que le agrega funcionalidad de comunicación remota.&lt;/p&gt;  &lt;p&gt;Esta es la lista de lo que quiero implementar:&lt;/p&gt;  &lt;p&gt;- Arrancar un host local en una dirección (máquina física, puerta)&lt;/p&gt;  &lt;p&gt;- Conetar con un host remoto dada una dirección&lt;/p&gt;  &lt;p&gt;- Conectar a un host remoto y enviarle la dirección de un host (local o remoto) para que pueda ubicarlo y enviarle trabajo&lt;/p&gt;  &lt;p&gt;- Ejecutar un callback (función, rutina) local cuando un host local reciba la dirección de un nuevo host existente en alguna máquina (una especie de OnRegisterHost).&lt;/p&gt;  &lt;p&gt;- Enviar un comando definido localmente (en el programa enviador) a un host remoto, y ejecutar en ese host remoto.&lt;/p&gt;  &lt;p&gt;- Enviar una expresión definida localmente a un host remoto y evaluarla en ese host remoto, retornando un resultado al host llamador.&lt;/p&gt;  &lt;p&gt;- Enviar una función/subrutina definida localmente, a un host remoto, enviarle parámetros y evaluarla/ejecutarla en el host remoto.&lt;/p&gt;  &lt;p&gt;- Enviar un texto al host remoto, parsearlo y ejecutarlo como comando.&lt;/p&gt;  &lt;p&gt;- Enviar un texto al host remoto, parsearlo y evaluarlo como expresión, devolviendo un resultado.&lt;/p&gt;  &lt;p&gt;- Enviar el contenido de un archivo local a un host remoto, parsearlo y ejecutarlo.&lt;/p&gt;  &lt;p&gt;- Obtener la lista de host locales registrados en la máquine (machine) actual.&lt;/p&gt;  &lt;p&gt;- Obtener la lista de host remotos registrados en la Machine.Current.&lt;/p&gt;  &lt;p&gt;- Enviar un valor local a una variable o left value expression a un host remoto.&lt;/p&gt;  &lt;p&gt;- Enviar una copia de un DynamicObject a un servidor remoto (tengo que resolver qué pasas si es DynamicObject con una clase asociada)&lt;/p&gt;  &lt;p&gt;- Enviar una referencia a un objeto DynamicObject al host remoto, para usarla allá como un proxy al objecto original, que sigue residiendo en el host local.&lt;/p&gt;  &lt;p&gt;- Enviar una copia de un agente a un host remoto, y arrancarlo para que ejecute tareas allá.&lt;/p&gt;  &lt;p&gt;- Exportar un archivo local con código fuente AjSharp, para ser usado en cualquier Include(“…”) que aparezca en el proceso de parseo del host remoto.&lt;/p&gt;  &lt;p&gt;- Exportar un assembly local a un host remoto (tengo que decidir si ahora necesito o no esta feature, interesante).&lt;/p&gt;  &lt;p&gt;Otro punto más:&lt;/p&gt;  &lt;p&gt;- Una aplicación de ejemplo, como “proof of concept”. Podría ser un web crawler distribuido, o la implementación de un algoritmo genético distribuido.&lt;/p&gt;  &lt;p&gt;Pueden ver el progreso en:&lt;/p&gt;  &lt;p&gt;&lt;a title="http://code.google.com/p/ajcodekatas/source/browse/#svn/trunk/AjLanguage" href="http://code.google.com/p/ajcodekatas/source/browse/#svn/trunk/AjLanguage"&gt;http://code.google.com/p/ajcodekatas/source/browse/#svn/trunk/AjLanguage&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Agregando todas estas features, y tener además go routines, futures, channels, y agentes, está haciendo interesante a este proyecto. Y me estoy “divigtiendo como loco” :-):-)&lt;/p&gt;  &lt;p&gt;Nos leemos!&lt;/p&gt;  &lt;p&gt;Angel “Java” Lopez    &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1768445" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx">AjSharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_F300_digo+Abierto/default.aspx">Proyectos de Código Abierto</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Aplicaciones+Distribuidas/default.aspx">Aplicaciones Distribuidas</category></item><item><title>AjSharp distribuido: Primeros pasos</title><link>http://msmvps.com/blogs/lopez/archive/2010/05/18/distributed_2D00_ajsharp_2D00_first_2D00_steps.aspx</link><pubDate>Tue, 18 May 2010 12:22:12 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1765783</guid><dc:creator>lopez</dc:creator><slash:comments>3</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1765783</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/05/18/distributed_2D00_ajsharp_2D00_first_2D00_steps.aspx#comments</comments><description>&lt;p&gt;Fue un gran fin de semana, con code kata. En la tarde del sábado, comencé a jugar con serialización de comandos en mi intérprete &lt;a href="http://en.wordpress.com/tag/ajsharp/" target="_blank"&gt;AjSharp&lt;/a&gt;:&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/ajsharp10.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;En ese momento estaba usando Windows Communication Foundation, con simple BasicHttpBindind y address. Elegí serializar comandos y expresiones en arreglos de bytes, usando BinaryFormatter, y enviarlos via WCF básico (No me gusta pelearme con serialización WCF).&lt;/p&gt;  &lt;p&gt;Entonces, el domungi, escribí una implementación usando remoting. Es una mejor aproximación a esta situación: remoting me de soporte “out-of-the.box” para serialización de grafos de objetos, y el manejo de MarshalByRefObject, lo que es bueno para mi proyecto.&lt;/p&gt;  &lt;p&gt;Mis primeros intentos usando remoting:&lt;/p&gt;  &lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/ajsharp11.png" alt="" /&gt; &lt;/p&gt;  &lt;p&gt;Noten el uso de las nuevas keywords &lt;strong&gt;expression&lt;/strong&gt; y &lt;strong&gt;command&lt;/strong&gt;. En este comando:&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;a = expression b+c;&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;se asigna una expresión b+c (pendiente de evaluación) a una variable local a. Podemos evaluarla con:&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;result = a.Evaluate(Machine.Environment);&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;(Machine es la máquina actual en ejecución, tiene un .Environment global, donde están los bindings para b y c, sus valores asociados).&lt;/p&gt;  &lt;p&gt;El comando:&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;a = command PrintLine(“Hello, world”);&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;no imprime un mensaje. Almacena el comando en una variable local, para ser ejecutado más adelante como:&lt;/p&gt;  &lt;p&gt;&lt;font face="Consolas"&gt;a.Execute(Machine.Environment);&lt;/font&gt;&lt;/p&gt;  &lt;p&gt;En el ejemplo de arriba, podemos arrancar a un servidor programáticamente. Podemos también crear el objeto proxy a ese servidor en el cliente. Y entonces, podemos invocar comandos, o evaluar expressiones, en el otro servidor. Después de tener eso andando, agregué el llamado de funciones, pasando argumentos al servidor. Esta es la principal interface que fue surgiendo, IHost:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="font-size:12px;margin:0em;width:100%;font-family:consolas,courier,monospace;background-color:#ffffff;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;interface&lt;/span&gt; IHost
    {
        &lt;span style="color:#008000;"&gt;// Host Id&lt;/span&gt;
        Guid Id { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt;; }
        &lt;span style="color:#008000;"&gt;// Host Invocation&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Execute(ICommand command);
        &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; Evaluate(IExpression expression);
        &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; Invoke(ICallable function, &lt;span style="color:#0000ff;"&gt;params&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt;[] arguments);
        &lt;span style="color:#008000;"&gt;// Others... Work in progress... to review&lt;/span&gt;
    }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Un host se ejecuta en una máquina, y expone el acceso a esa máquina, con invocaciones de comandos, funciones y evaluaciones de expresiones. Hay host que son locales (class Host), y hosts que exponen su funcionalidad via remoting (RemotingHostServer), y que se consumen desde su correspondiente cliente proxy (RemotingHostClient). Estoy también trabajando en tener esas clases en WCF: hay un WcfHostServer, WcfHostClient, pero tengo que luchar con temas de serialización, todavía.&lt;/p&gt;

&lt;p&gt;Debería agregar el pasar strings conteniendo commandos y expresiones, y que el servidor receptor los parsee y ejecute/evalúe (sería más fácil que enviar lo que estoy enviando ahora, el ICommand, IExpression ya armado).&lt;/p&gt;

&lt;p&gt;Después de las pruebas exitosas de arriba, agregué “syntax sugar”: no hay que minimizar el efecto de una buena sintaxis, que puede simplificar el uso de una característica. Agregué la keyword &lt;strong&gt;at&lt;/strong&gt; en AjSharp:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/ajsharp12.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;Podemos invocar un comando en el otro server usando:&lt;/p&gt;

&lt;p&gt;&lt;font face="Consolas"&gt;at &amp;lt;host&amp;gt; &amp;lt;command&amp;gt;;&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;o podemos evaluar una expresión en otro servidor y devolver el resultado:&lt;/p&gt;

&lt;p&gt;&lt;font face="Consolas"&gt;localvar = at &amp;lt;host&amp;gt; &amp;lt;expression&amp;gt;;&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;Tengo que trabajar más en algunos detalles de serialización. Resolví parte del callback al servidor. Esto es:&lt;/p&gt;

&lt;p&gt;&lt;font face="Consolas"&gt;at host { adam = new DynamicObject(); adam.Name = “Adam”; adam.Age = 800; } 
    &lt;br /&gt;myadam = at host adam;&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;adam se crea en el host remoto. La variable local myadam, cuando uso remoting, es en realidad un transparent proxy que apunta al DynamicObject que todavía está en el host donde fue creado (hasta ahora, los DynamicObject los he puesto descendiendo de MarshalByRefObject; estoy pensando cambiar esta decisión, y hacer que se serializen por defecto, y agregar un método, tipo obj.AsProxy() para generar una referencia MarshalByRefObject explícitamente cuando el programador así lo solicite). Pero el transparent proxy que recibo no puede ser invocado directamente: no tiene un canal asociado de comunicación. Así que agregué un wrapper a ese objeto cuando lo recibo en el cliente. Si invocamos algo de myadam, como en:&lt;/p&gt;

&lt;p&gt;&lt;font face="Consolas"&gt;PrintLine(myadam.Name); 
    &lt;br /&gt;myadam.Name = “NewAdam”;&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;el wrapper redirecciona todo a que se ejecute en el servidor que fue invocado, y la operación se ejecuta en el servidor.&lt;/p&gt;

&lt;p&gt;Como siempre, pueden bajar y examinar el código desde:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://go2.wordpress.com/?id=725X1342&amp;amp;site=ajlopez.wordpress.com&amp;amp;url=http%3A%2F%2Fcode.google.com%2Fp%2Fajcodekatas%2Fsource%2Fbrowse%2F&amp;amp;sref=http%3A%2F%2Fajlopez.wordpress.com%2F2010%2F03%2F15%2Fscripting-watin-using-ajsharp%2F"&gt;http://code.google.com/p/ajcodekatas/source/browse/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;en el directorio trunk/AjLanguage.&lt;/p&gt;

&lt;p&gt;Tengo que confesar que estoy orgulloso de este avance en mi intérprete. Podría extender, llegado el caso, esta capacidad para otros intérpretes, como AjIo,, AjTalk (era la idea inicial de AjTalk, tener un Smalltalk-like VM con objetos distribuidos). Nació sólo como una idea, pero va tomando forma, un lenguaje distribuido es el camino a explorar para poder aprovechar más máquinas en algunas tareas. El proyecto es un bebé todavía, pero es mi bebé, y me divierte mucho codificarlo.&lt;/p&gt;

&lt;p&gt;Nos leemos!&lt;/p&gt;

&lt;p&gt;Angel “Java” Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1765783" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx">AjSharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_F300_digo+Abierto/default.aspx">Proyectos de Código Abierto</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Aplicaciones+Distribuidas/default.aspx">Aplicaciones Distribuidas</category></item><item><title>Haciendo Scripting sobre WatiN usando AjSharp</title><link>http://msmvps.com/blogs/lopez/archive/2010/03/16/haciendo-scripting-sobre-watin-usando-ajsharp.aspx</link><pubDate>Tue, 16 Mar 2010 14:41:52 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1761724</guid><dc:creator>lopez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1761724</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/03/16/haciendo-scripting-sobre-watin-usando-ajsharp.aspx#comments</comments><description>&lt;p&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx" target="_blank"&gt;AjSharp&lt;/a&gt; es un lenguaje interpretado que escribí en C#. Es un lenguaje dinámico, con &lt;a href="http://msmvps.com/blogs/lopez/archive/2009/12/27/ajsharp_2D00_dynamic_2D00_classes_2D00_and_2D00_objects.aspx" target="_blank"&gt;clases y objetos dinámicos&lt;/a&gt;, &lt;a href="http://msmvps.com/blogs/lopez/archive/2010/02/06/functional_2D00_values_2D00_in_2D00_ajsharp.aspx" target="_blank"&gt;valores funcionales&lt;/a&gt;, &lt;a href="http://msmvps.com/blogs/lopez/archive/2009/12/31/channels_2D00_and_2D00_goroutines_2D00_in_2D00_ajsharp_2D00_part_2D00_2.aspx" target="_blank"&gt;canales y gorutinas&lt;/a&gt;, entidades similares &lt;a href="http://msmvps.com/blogs/lopez/archive/2010/02/23/web_2D00_crawler_2D00_using_2D00_agents_2D00_and_2D00_ajsharp.aspx" target="_blank"&gt;a agentes&lt;/a&gt;, acceso a objetos .NET nativos. Fue creado como un derivativode mi trabajo previo en AjBasic, el lenguaje interpretado y dinámico que use como base de &lt;a href="http://www.codeplex.com/ajgenesis" target="_blank"&gt;AjGenesis&lt;/a&gt;, mi proyecto de generación de código. Mi plan es unificar ambos lenguajes usando el núcleo AjLanguage, y agregarlos al AjGenesis, permitiendo también el uso de to otros lenguajes, como plugins. Pero eso todavía está en plan.&lt;/p&gt;  &lt;p&gt;El código de esto post está en el trunk del AjCodeKatas Google Project:&lt;/p&gt;  &lt;p&gt;&lt;a title="http://code.google.com/p/ajcodekatas/source/browse/" href="http://code.google.com/p/ajcodekatas/source/browse/"&gt;http://code.google.com/p/ajcodekatas/source/browse/&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;en trunk/AjLanguage/Src/AjSharp.Examples&lt;/p&gt;  &lt;p&gt;Uno de los objetivos de diseño de AjSharp es servir como un shell liviano para invocar librerías .NET. Como prueba de concepto, escribí una simple clase para acceder a &lt;a href="http://watin.sourceforge.net/" target="_blank"&gt;WatiN&lt;/a&gt;, la librería de automatización de pruebas web. Esta es la clase que estoy usando (y aplicando en un proyecto de desarrollo actual):&lt;/p&gt;  &lt;pre&gt;&lt;pre style="font-size:12px;margin:0px;width:100%;font-family:consolas,courier,monospace;background-color:#ffffff;"&gt;&lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Wat
{
  var Browser;
  
  function Wat()
  {
    WatiN.Core.Settings.WaitForCompleteTimeOut = 480;
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Browser = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; WatiN.Core.IE();
  }
  
  sub Browse(url)
  {
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Browser.GoToNoWait(url);
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Browser.WaitForComplete(480);
  }
  
  function Button(name)
  {
    button = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Browser.Button(name);
    
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (button.Exists)
      &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; button;
      
    button = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Browser.Button(WatiN.Core.Find.ByName(name));
    
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (button.Exists)
      &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; button;
      
    button = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Browser.Button(WatiN.Core.Find.ByValue(name));
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (button.Exists)
      &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; button;
      
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;;
  }
  
  function TextField(name)
  {
    textfield = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Browser.TextField(name);
    
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (textfield.Exists)
      &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; textfield;
      
    textfield = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Browser.TextField(WatiN.Core.Find.ByName(name));
    
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (textfield.Exists)
      &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; textfield;
      
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;;
  }
  
  function Link(name)
  {
    link = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Browser.Link(name);
    
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (link.Exists)
      &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; link;
      
    link = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Browser.Link(WatiN.Core.Find.ByUrl(name));
    
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; link;
    
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (link.Exists)
      &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; link;
      
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;;
  }
  
  function Contains(text)
  {
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Browser.ContainsText(text);
  }
  
  sub Close()
  {
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Browser.Close();
  }
}
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Se puede extenderla con otras características. Igual deja expuesto el WatiN browser, por si necesitamos algo que no esté expuesto en el código de arriba. Un ejemplo de uso:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="font-size:12px;margin:0px;width:100%;font-family:consolas,courier,monospace;background-color:#ffffff;"&gt;Include(&amp;quot;&lt;span style="color:#8b0000;"&gt;Tests.ajs&lt;/span&gt;&amp;quot;);
System.Reflection.Assembly.Load(&amp;quot;&lt;span style="color:#8b0000;"&gt;WatiN.Core&lt;/span&gt;&amp;quot;);
Include(&amp;quot;&lt;span style="color:#8b0000;"&gt;Wat.ajs&lt;/span&gt;&amp;quot;);
wat = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Wat();
wat.Browse(&amp;quot;&lt;span style="color:#8b0000;"&gt;http://google.com&lt;/span&gt;&amp;quot;);
wat.TextField(&amp;quot;&lt;span style="color:#8b0000;"&gt;q&lt;/span&gt;&amp;quot;).TypeText(&amp;quot;&lt;span style="color:#8b0000;"&gt;Angel Java Lopez&lt;/span&gt;&amp;quot;);
wat.Button(&amp;quot;&lt;span style="color:#8b0000;"&gt;Google Search&lt;/span&gt;&amp;quot;).Click();
Assert(wat.Contains(&amp;quot;&lt;span style="color:#8b0000;"&gt;ajlopez.com&lt;/span&gt;&amp;quot;), &amp;quot;&lt;span style="color:#8b0000;"&gt;No content&lt;/span&gt;&amp;quot;);
wat.Browse(&amp;quot;&lt;span style="color:#8b0000;"&gt;http://www.ajlopez.net/&lt;/span&gt;&amp;quot;);
Assert(wat.Contains(&amp;quot;&lt;span style="color:#8b0000;"&gt;Java&lt;/span&gt;&amp;quot;), &amp;quot;&lt;span style="color:#8b0000;"&gt;No content&lt;/span&gt;&amp;quot;);
Assert(wat.Link(&amp;quot;&lt;span style="color:#8b0000;"&gt;http://ajlopez.zoomblog.com/&lt;/span&gt;&amp;quot;).Exists, &amp;quot;&lt;span style="color:#8b0000;"&gt;No link 4&lt;/span&gt;&amp;quot;);
wat.Link(&amp;quot;&lt;span style="color:#8b0000;"&gt;http://ajlopez.zoomblog.com/&lt;/span&gt;&amp;quot;).Click();
Assert(wat.Contains(&amp;quot;&lt;span style="color:#8b0000;"&gt;Ciencia&lt;/span&gt;&amp;quot;), &amp;quot;&lt;span style="color:#8b0000;"&gt;No content 2&lt;/span&gt;&amp;quot;);
wat.Close();
exit;
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;El único problema que encontré al invocar a WatiN, es su requerimiento de ejecutarse dentro de un STAThread (Single Thread Apartment model). Así que cambié el método de main de AjSharp.Console, agregádole el atributo STAThread (¿habrá forma de elegir ese modelo por código, al lanzar un thread?). Estoy usando este tipo de scripts para probar una aplicación web real en desarrollo en un equipo ágil. Una cosa que podría agregar es soporte de excepciones y logueo de los mensajes de Assert (esto no es de Wat, sino de Test.ajs).&lt;/p&gt;

&lt;p&gt;Pueden usar utilitarios más robustos sobre WatiN, como el &lt;a href="http://www.codeplex.com/wax/" target="_blank"&gt;Wax&lt;/a&gt;, que permite escribir tests usando planillas Excel. Por ahora, con lo que uso de arriba, me ha sido suficiente en el proyecto actual. Es un buen ejercicio para ir haciendo dog-fooding y probar las capacidades, fortalezas y debilidades de AjSharp en un requerimiento real.&lt;/p&gt;

&lt;p&gt;Nos leemos!&lt;/p&gt;

&lt;p&gt;Angel “Java” Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1761724" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx">AjSharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Testing/default.aspx">Testing</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_F300_digo+Abierto/default.aspx">Proyectos de Código Abierto</category></item><item><title>Web Crawler usando Agentes y AjSharp</title><link>http://msmvps.com/blogs/lopez/archive/2010/02/23/web_2D00_crawler_2D00_using_2D00_agents_2D00_and_2D00_ajsharp.aspx</link><pubDate>Tue, 23 Feb 2010 10:16:11 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1759190</guid><dc:creator>lopez</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1759190</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/02/23/web_2D00_crawler_2D00_using_2D00_agents_2D00_and_2D00_ajsharp.aspx#comments</comments><description>&lt;p&gt;El pasado año, escribí un ejemplo de web crawler usando mensajes, detalles en los posts:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ajlopez.wordpress.com/2009/03/09/distributed-web-crawler-using-ajmessages/" target="_blank"&gt;Distributed Web Crawler using AjMessages&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2009/03/10/web-crawler-distribuido-usando-ajmessages.aspx" target="_blank"&gt;Web Crawler distribuido usando AjMessages&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Antes, escribí otros ejemplos usando DSS/CCR, tecnologías incluidas en &lt;a href="http://www.microsoft.com/robotics"&gt;Microsoft Robotics Developer Studio&lt;/a&gt;:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ajlopez.wordpress.com/2008/06/15/distributed-agents-using-dssvpl/" target="_blank"&gt;Distributed Agents using DSS/VPL&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://ajlopez.wordpress.com/2008/05/25/web-crawler-example-using-dss-decentralized-software-services/" target="_blank"&gt;Web Crawler example using DSS (Decentralized Software Services)&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2008/10/10/aplicaciones-distribuidas-con-ajmessages-usando-dss-ccr.aspx"&gt;Aplicaciones Distribuidas con AjMessages usando DSS/CCR&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2008/05/28/ejemplo-de-web-crawler-usando-dss-decentralized-software-services.aspx" target="_blank"&gt;Ejemplo de Web Crawler usando DSS&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Ahora, escribí un ejemplo local (no distribuido) usando agentes en &lt;a href="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx" target="_blank"&gt;AjSharp&lt;/a&gt;. Recordemos, cada agente se ejecuta en su propio thread, y sus invocaciones son encoladas, y ejecutadas de una en una. Más sobre agentes en AjSharp en:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ajlopez.wordpress.com/2010/02/12/agents-in-ajsharp-part-1/" target="_blank"&gt;Agents in AjSharp (Part 1)&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/02/13/agents_2D00_in_2D00_ajsharp_2D00_part_2D00_1.aspx" target="_blank"&gt;Agentes en AjSharp (Parte 1)&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://ajlopez.wordpress.com/2010/02/18/agents-in-ajsharp-part-2/" target="_blank"&gt;Agents in AjSharp (Part 2)&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/02/19/agents_2D00_in_2D00_ajsharp_2D00_part_2D00_2.aspx" target="_blank"&gt;Agentes en AjSharp (Parte 2)&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Hace dos días, tomé el código de mis anteriores ejemplos, y lo reensamblé en agentes de AjSharp. Este es el primer resultado de ese experimiento. Primero, definí un objeto para armara una red de agentes que se ocupen de visitar un sitio, y lanzar el proceso:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#008000;"&gt;// Build and launch agents&lt;/span&gt;
&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; WebCrawler
{
  sub Process(url, fn)
  {
    uri = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; System.Uri(url);
    downloader = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Downloader();
    harvester = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Harvester();
    resolver = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Resolver(uri,5);
    processor = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Processor(fn);
    
    downloader.Harvester = harvester;
    downloader.Processor = processor;
    harvester.Resolver = resolver;
    resolver.Downloader = downloader;
    
    downloader.Process(uri, 0);
  }
}&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;El Downloader toma una URI, baja su contenido y envía el resultado a dos agentes asociados: Processor y Harvester. El parámetro Depth indica la profundidad de esta página en el proceso de crawling del sitio:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#008000;"&gt;// Downloads a page&lt;/span&gt;
agent Downloader 
{
  sub Process(uri,depth)
  {
    client = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; System.Net.WebClient();
    content = client.DownloadString(uri);
    PrintLine(&amp;quot;&lt;span style="color:#8b0000;"&gt;Downloaded: &lt;/span&gt;&amp;quot; + uri);
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Harvester.Process(uri,depth,content);
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Processor.Process(uri, content);
  }
}&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;The Processor executes a user function/routine, receiving the URI and its retrieved content:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#008000;"&gt;// Process the content retrieved&lt;/span&gt;
agent Processor
{
  function Processor(fn)
  {
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.fn = fn; &lt;span style="color:#008000;"&gt;// function to invoke&lt;/span&gt;
  }
  
  sub Process(uri, content)
  {
    &lt;span style="color:#008000;"&gt;// Add your logic&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.fn(uri, content);
  }
}&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;El Harvester detecta otros enlaces en el contenido, y los envía, uno a uno, a otro agente, el Resolver:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#008000;"&gt;// Get links from page&lt;/span&gt;
agent Harvester
{
  sub Process(uri,depth,content)
  {
    matches = System.Text.RegularExpressions.Regex.Matches(content, &amp;quot;&lt;span style="color:#8b0000;"&gt;href=\\s*\&amp;quot;([^&amp;amp;\&amp;quot;]*)\&amp;quot;&lt;/span&gt;&amp;quot;);
    results = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; List();
    
    &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (match &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; matches) {
      &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt; = match.Groups[1].Value;
      
      &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (!results.Contains(&lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;))
        results.Add(&lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;);
    }
    
    &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (result &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; results) 
      &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (result.StartsWith(&amp;quot;&lt;span style="color:#8b0000;"&gt;http&lt;/span&gt;&amp;quot;))
        &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Resolver.Process(&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; System.Uri(result), depth+1);
  }
}
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;El Resolver mantiene una lista de URIs procesados, y filtra aquellas que no se encuentran en el host original. El proceso se limita entonces hasta una cierta profundidad de exploración y dentro del sitio original:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#008000;"&gt;// Filter invalid or already processed links&lt;/span&gt;
agent Resolver
{
  var processed = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; List();  
  
  function Resolver(uri,maxdepth)
  {
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.host = uri.Host;
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.maxdepth = maxdepth;
  }
  
  sub Process(uri,depth) 
  {
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (depth &amp;gt; &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.maxdepth)
      &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt;;
      
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (uri.Host != &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.host)
      &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt;;
    
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (uri.Scheme != System.Uri.UriSchemeHttp &amp;amp;&amp;amp; uri.Scheme != System.Uri.UriSchemeHttps)
      &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt;;
      
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (processed.Contains(uri))
      &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt;;
      
    processed.Add(uri);
      
    PrintLine(&amp;quot;&lt;span style="color:#8b0000;"&gt;New Link: &lt;/span&gt;&amp;quot; + uri);
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Downloader.Process(uri,depth);     
  }
}&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Estos son ejemplos de uso, creando dos redes de agentes, dedicados a obtener el contenido de dos sitios:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#008000;"&gt;// Example&lt;/span&gt;
WebCrawler.Process(&amp;quot;&lt;span style="color:#8b0000;"&gt;http://ajlopez.wordpress.com&lt;/span&gt;&amp;quot;, function(uri,content) { PrintLine(&amp;quot;&lt;span style="color:#8b0000;"&gt;From ajlopez.wordpress &lt;/span&gt;&amp;quot;+uri);});
WebCrawler.Process(&amp;quot;&lt;span style="color:#8b0000;"&gt;http://ajlopez.zoomblog.com&lt;/span&gt;&amp;quot;, function(uri,content) { PrintLine(&amp;quot;&lt;span style="color:#8b0000;"&gt;From ajlopez.zoomblog &lt;/span&gt;&amp;quot;+uri);});
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Pueden bajar el AjSharp desde el trunk:&lt;/p&gt;

&lt;p&gt;&lt;a title="http://code.google.com/p/ajcodekatas/source/browse/#svn/trunk/AjLanguage" href="http://code.google.com/p/ajcodekatas/source/browse/#svn/trunk/AjLanguage"&gt;http://code.google.com/p/ajcodekatas/source/browse/#svn/trunk/AjLanguage&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El código de web crawler está en Examples/WebCrawler.ajs dentro del proyecto AjSharp.Console. Despues de compilar a este programa de consola, pueden lanzar:&lt;/p&gt;

&lt;p&gt;&lt;font face="Consolas"&gt;AjSharp.Console Examples/WebCrawler.ajs&lt;/font&gt;&lt;/p&gt;

&lt;p&gt;Esta es una salida parcial:&lt;/p&gt;

&lt;p&gt;&lt;img src="http://www.ajlopez.com/images/articles2/ajsharpwebcrawler01.png" alt="" /&gt; &lt;/p&gt;

&lt;p&gt;Pueden ver el ejemplo completo en Pastie &lt;a title="http://pastie.org/835926" href="http://pastie.org/835926"&gt;http://pastie.org/835926&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Próximo paso: usar agentes distribuidos. Hay dos caminos a explorar: uno, declarar que algunos agentes sean distribuidos usando código adicional o configuración, pero sin cambiar el código original. Dos, hacer la distribución explícita en el código.&lt;/p&gt;

&lt;p&gt;Nos leemos!&lt;/p&gt;

&lt;p&gt;Angel “Java” Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1759190" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx">AjSharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_F300_digo+Abierto/default.aspx">Proyectos de Código Abierto</category></item><item><title>Cantidad variable de Argumentos en AjSharp</title><link>http://msmvps.com/blogs/lopez/archive/2010/02/21/variable_2D00_length_2D00_arguments_2D00_in_2D00_ajsharp.aspx</link><pubDate>Sun, 21 Feb 2010 13:44:14 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1758850</guid><dc:creator>lopez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1758850</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/02/21/variable_2D00_length_2D00_arguments_2D00_in_2D00_ajsharp.aspx#comments</comments><description>&lt;p&gt;En mis experimentos con agentes, usando el intérprete &lt;a href="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx" target="_blank"&gt;AjSharp&lt;/a&gt;, encontré que me faltaba algo para implementar lo que quería: soportar una cantidad variable de parámetros en la llamada a una función, rutina o método. Así, que volví a codificar, con el sombrero de Test-Driven Development puesto, durante un desayuno de codificación, y salió lo que describo en este post.&lt;/p&gt;  &lt;p&gt;Tuve que implementar dos facetas de esa característica. Primero, la declaración de recibir una cantidad variable de argumentos:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="font-size:12px;margin:0em;width:100%;font-family:consolas,courier,monospace;background-color:#ffffff;"&gt;function FirstParameter(pars...)
{
	&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (pars.Length&amp;gt;0)
		&lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; pars[0];
		
	&lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;;
}
function SecondParameter(pars...)
{
	&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (pars.Length&amp;gt;1)
		&lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; pars[1];
		
	&lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;;
}
result = FirstParameter(1,2,3);		&lt;span style="color:#008000;"&gt;// 1&lt;/span&gt;
result2 = SecondParameter(1,2,3);	&lt;span style="color:#008000;"&gt;// 2&lt;/span&gt;
result3 = SecondParameter();		&lt;span style="color:#008000;"&gt;// null&lt;/span&gt;
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;La otra parta, qué pasa si quiero usar los parámetros recibidos con … (tres puntos) como parámetros para entregar a otra función? El &lt;strong&gt;pars…&lt;/strong&gt; recibido es un arreglo de objetos. Para usarlo pasándolo no como arreglo, sino como los propios valores “expandidos”, usé el mismo operador … (tres puntos), pero ahora, desde la invocación:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="font-size:12px;margin:0em;width:100%;font-family:consolas,courier,monospace;background-color:#ffffff;"&gt;function FirstParameter(pars...)
{
	&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (pars.Length&amp;gt;0)
		&lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; pars[0];
		
	&lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;;
}
function SecondParameter(pars...)
{
	&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (pars.Length&amp;gt;1)
		&lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; pars[1];
		
	&lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;;
}
function JustDoIt(fn,pars...)
{
	&lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; fn(pars...);
}
result = JustDoIt(FirstParameter,1,2,3);		&lt;span style="color:#008000;"&gt;// 1&lt;/span&gt;
result2 = JustDoIt(SecondParameter,1,2,3);	&lt;span style="color:#008000;"&gt;// 2&lt;/span&gt;
result3 = JustDoIt(SecondParameter);		&lt;span style="color:#008000;"&gt;// null&lt;/span&gt;
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Curiosamente, hace dos días, encontré el lenguaje&lt;/p&gt;

&lt;p&gt;&lt;a href="http://jashkenas.github.com/coffee-script/" target="_blank"&gt;CoffeeScript&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;que compila a JavaScript normal. En la página de tutorial, encontré un término nuevo para mí : Splats para denominar el operador … (tres puntos). Decidí usar ese operador hace unas semanas, y ahora me lo encuentro ahí. No recuerdo cuándo fue que se sembró en mi mente la idea de usar ese operador.&lt;/p&gt;

&lt;p&gt;Podría emplear este operador en algún ejemplo de agente.&lt;/p&gt;

&lt;p&gt;Nos leemos!&lt;/p&gt;

&lt;p&gt;Angel &amp;quot;Java&amp;quot; Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1758850" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx">AjSharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_F300_digo+Abierto/default.aspx">Proyectos de Código Abierto</category></item><item><title>Agentes en AjSharp (Parte 2)</title><link>http://msmvps.com/blogs/lopez/archive/2010/02/19/agents_2D00_in_2D00_ajsharp_2D00_part_2D00_2.aspx</link><pubDate>Fri, 19 Feb 2010 10:23:38 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1758484</guid><dc:creator>lopez</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1758484</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/02/19/agents_2D00_in_2D00_ajsharp_2D00_part_2D00_2.aspx#comments</comments><description>&lt;p&gt;Estuve implementando una especie de soporte de agentes en mi intérprete &lt;a href="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx" target="_blank"&gt;AjSharp&lt;/a&gt;. En el anterior post:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ajlopez.wordpress.com/2010/02/12/agents-in-ajsharp-part-1/" target="_blank"&gt;Agents in AjSharp (Part 1)&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/02/13/agents_2D00_in_2D00_ajsharp_2D00_part_2D00_1.aspx" target="_blank"&gt;Agentes en AjSharp (Parte 1)&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;describí algo de esa implementación y las principales características. Dos puntos para recordar:&lt;/p&gt;  &lt;p&gt;- Cada agente ejecuta en su propio thread    &lt;br /&gt;- Cada agente tiene una cola de proceso para recibir sus invocaciones (método y argumentos)&lt;/p&gt;  &lt;p&gt;Quiero mostrar en este post dos simples ejemplos de uso. Primero, uno donde los agentes se encadenan, implementando algo así como message passing, procesando un dato y produciendo resultados.&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;agent IncrementAgent 
{
  function IncrementAgent(next, channel)
  {
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.channel = channel;
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.next = next;
  }
  
  sub Process(&lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;)
  {
    newvalue = &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt; + 1;
    
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (channel)
      channel &amp;lt;- newvalue;
      
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (next)
      next.Process(newvalue);
  }
}
channel = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Channel();
thirdAgent = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; IncrementAgent(&lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;, channel);
secondAgent = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; IncrementAgent(thirdAgent, channel);
firstAgent = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; IncrementAgent(secondAgent, channel);
firstAgent.Process(0);
&lt;span style="color:#0000ff;"&gt;for&lt;/span&gt; (k = 1; k &amp;lt;= 3; k++)
  result = result + &amp;lt;-channel; 
&lt;span style="color:#008000;"&gt;// result == 1 + 2 + 3 == 6&lt;/span&gt;
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Vean que cada agente es un eslabon de la cadena de proceso, y que se usa un channel para coleccionar los resultados. La combinación de colaboración de objetos se puede hacer en formas más complejas.&lt;/p&gt;

&lt;p&gt;En el segundo ejemplo, implementé el &lt;a href="http://en.wikipedia.org/wiki/Collatz_conjecture" target="_blank"&gt;problema de Collatz&lt;/a&gt; usando una ronda de dos agentes:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (number % 2)
    {
      &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Next.Process(number, list);
      &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt;;
    }
    
    list.Add(number);
  
    number = number / 2;
    
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Next.Process(number, list);
  }
}
agent OddAgent 
{
  sub Process(number, list)
  {
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; ((number % 2)==0)
    {
      &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Next.Process(number, list);
      &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt;;
    }
    
    list.Add(number);
    
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (number == 1) 
    {
      &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Channel &amp;lt;- list;
      &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt;;
    }
    
    number = number * 3 + 1;
    
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Next.Process(number, list);
  }
}
channel = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Channel();
even = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; EvenAgent();
odd = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; OddAgent();
even.Channel = channel;
even.Next = odd;
odd.Channel = channel;
odd.Next = even;
even.Process(22, &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; List());
result = &amp;lt;-channel;
&lt;span style="color:#008000;"&gt;// result = { 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1 }&lt;/span&gt;
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Más sobre la interesante conjetura de Collatz:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www-personal.ksu.edu/~kconrow/" target="_blank"&gt;Collatz 3n+1 Problem Structure&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://www.programming-challenges.com/pg.php?page=downloadproblem&amp;amp;probid=110101&amp;amp;format=html" target="_blank"&gt;Programming 3n+1 problem&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Estos son ejemplos simples. Quiero implementar un web crawler, o un web scraping, o un algoritmo genético en paralelo, usando agentes. También tengo como próximo paso: agentes distribuidos.&lt;/p&gt;

&lt;p&gt;Nos leemos!&lt;/p&gt;

&lt;p&gt;Angel “Java” Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1758484" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx">AjSharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_F300_digo+Abierto/default.aspx">Proyectos de Código Abierto</category></item><item><title>Default methods en AjSharp</title><link>http://msmvps.com/blogs/lopez/archive/2010/02/16/default_2D00_methods_2D00_in_2D00_ajsharp.aspx</link><pubDate>Tue, 16 Feb 2010 10:02:23 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1757839</guid><dc:creator>lopez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1757839</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/02/16/default_2D00_methods_2D00_in_2D00_ajsharp.aspx#comments</comments><description>&lt;p&gt;En estos días, agregué lo que llamo default methods en &lt;a href="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx" target="_blank"&gt;AjSharp&lt;/a&gt;, mi intérprete de código abierto. ¿Qué es un default method en la jerga de AjSharp? Me inspiré por el mensaje #doesnotunderstand que está en los objetos Smalltalk. AjSharp es un intérprete dinámico, así que podemos invocar cualquier método, aún uno no existente. Si el método no está definido, pero hay un default method declarado, entonces éste es invocado, recibiendo dos parámetors, el nombre del método original, y sus argumentos. &lt;/p&gt;  &lt;p&gt;Primer ejemplo:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; Incrementor
{
  function Increment(n) 
  {
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; n+1;
  }
}
&lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Proxy
{
  var Object;
  
  function Proxy(obj)
  {
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Object = obj;
  }
  
  &lt;span style="color:#0000ff;"&gt;default&lt;/span&gt; function InvokeMethod(name, parameters)
  {
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Object.Invoke(name,parameters);
  }
}
proxy = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Proxy(Incrementor);
result = proxy.Increment(3); &lt;span style="color:#008000;"&gt;// result == 4&lt;/span&gt;
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;La palabra clave &lt;strong&gt;default&lt;/strong&gt; marca el default method (estoy aún reluctante a usa una palabra clave para esto, pero no tengo todavía otra idea para implementarlo). Notemos que esta implementación de proxy solamente funciona encapsulando instancias de &lt;strong&gt;DynamicObject&lt;/strong&gt;, que tienen un méetodo &lt;strong&gt;.Invoke&lt;/strong&gt;. Podría extenderlo para que maneje objetos CLR también.&lt;/p&gt;

&lt;p&gt;Por ahora, otro ejemplo sencillo:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Incrementor
{
  function Increment(n) 
  {
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; n+1;
  }
}
&lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; LoadBalancer
{
  var objects;
  var random;
  
  function LoadBalancer()
  {
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.random = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; System.Random();
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.objects = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; List();
  }
  
  sub Add(obj)
  {
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.objects.Add(obj);
  }
  
  &lt;span style="color:#0000ff;"&gt;default&lt;/span&gt; function InvokeMethod(name, parameters)
  {
    n = random.Next(objects.Count);
    
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.objects&lt;img src="http://msmvps.com/emoticons/emotion-45.gif" alt="No" /&gt;.Invoke(name,parameters);
  }
}
  
balancer = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; LoadBalancer();
balancer.Add(&amp;quot;&lt;span style="color:#8b0000;"&gt;Foo&lt;/span&gt;&amp;quot;);
&lt;span style="color:#0000ff;"&gt;for&lt;/span&gt; (k=1; k&amp;lt;=10; k++)
  balancer.Add(&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Incrementor());
  
result = 0;
&lt;span style="color:#0000ff;"&gt;for&lt;/span&gt; (k=0; k&amp;lt;4; k++)
  result = result + balancer.Increment(k);
  
&lt;span style="color:#008000;"&gt;// result == 1 + 2 + 3 + 4 == 10&lt;/span&gt;
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Es una especie de “load balancer”, que usa al azar, podría llamarlo&amp;#160; “distributor”. La instancia LoadBalancer envía cada llamada a método a uno de sus objetos, al azar.&lt;/p&gt;

&lt;p&gt;Podría escribir otro ejemplo, donde el balancer envía cada invocación a TODOS sus objetos. Tengo pensado usar estas características en agentes, en especial, en agentes distribuidos. Podría agregar default methods a objetos AjSharp (recuerde, AjSharp puede definir objetos sin clase asociada).&lt;/p&gt;

&lt;p&gt;Como siempre, el código está disponible en:&lt;/p&gt;

&lt;p&gt;&lt;a title="http://code.google.com/p/ajcodekatas/source/browse/#svn/trunk/AjLanguage" href="http://code.google.com/p/ajcodekatas/source/browse/#svn/trunk/AjLanguage"&gt;http://code.google.com/p/ajcodekatas/source/browse/#svn/trunk/AjLanguage&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nos leemos!&lt;/p&gt;

&lt;p&gt;Angel “Java” Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1757839" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx">AjSharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_F300_digo+Abierto/default.aspx">Proyectos de Código Abierto</category></item><item><title>Agentes en AjSharp (Parte 1)</title><link>http://msmvps.com/blogs/lopez/archive/2010/02/13/agents_2D00_in_2D00_ajsharp_2D00_part_2D00_1.aspx</link><pubDate>Sat, 13 Feb 2010 10:51:09 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1757103</guid><dc:creator>lopez</dc:creator><slash:comments>2</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1757103</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/02/13/agents_2D00_in_2D00_ajsharp_2D00_part_2D00_1.aspx#comments</comments><description>&lt;p&gt;Comencé a implementar ideas de agentes en mi intérprete &lt;a href="http://en.wordpress.com/tag/ajsharp/" target="_blank"&gt;AjSharp&lt;/a&gt;. Ya había explorado channel2, queue channels y futures en anteriores posts:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://go2.wordpress.com/?id=725X1342&amp;amp;site=wordpress.com&amp;amp;url=http%3A%2F%2Fajlopez.wordpress.com%2F2009%2F12%2F28%2Fchannels-and-goroutines-in-ajsharp-part-1%2F" target="_blank"&gt;Channels and GoRoutines in AjSharp (Part 1)&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://go2.wordpress.com/?id=725X1342&amp;amp;site=wordpress.com&amp;amp;url=http%3A%2F%2Fajlopez.wordpress.com%2F2009%2F12%2F30%2Fchannels-and-goroutines-in-ajsharp-part-2%2F" target="_blank"&gt;Channels and GoRoutines in AjSharp (Part 2)&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/01/03/goroutines_2D00_and_2D00_channels_2D00_in_2D00_c.aspx"&gt;GoRoutines y Canales en C#&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://ajlopez.wordpress.com/2010/01/02/goroutines-and-channels-in-c/"&gt;GoRoutines and Channels in C#&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://go2.wordpress.com/?id=725X1342&amp;amp;site=wordpress.com&amp;amp;url=http%3A%2F%2Fajlopez.wordpress.com%2F2010%2F01%2F25%2Fajsharp-implementing-futures%2F" target="_blank"&gt;AjSharp: Implementing Futures&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/01/28/ajsharp_2D00_implementing_2D00_futures.aspx" target="_blank"&gt;AjSharp: Implementando Futures&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://go2.wordpress.com/?id=725X1342&amp;amp;site=wordpress.com&amp;amp;url=http%3A%2F%2Fajlopez.wordpress.com%2F2010%2F01%2F27%2Fqueue-channels-in-ajsharp%2F" target="_blank"&gt;Queue Channels in AjSharp&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/01/29/queue_2D00_channels_2D00_in_2D00_ajsharp.aspx"&gt;Queue Channels en AjSharp&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;y una implementación paralela de un algoritmo directamente en C#:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ajlopez.wordpress.com/2010/02/07/genetic-algorithms-using-goroutines-and-channels-in-c/"&gt;Genetic Algorithms using GoRoutines and Channels in C#&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/02/08/genetic_2D00_algorithms_2D00_using_2D00_goroutines_2D00_and_2D00_channels_2D00_in_2D00_c.aspx" target="_blank"&gt;Algoritmos Genéticos usando GoRoutines y Channels en C#&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;pero sería interesante tener un modelo más claro para la computación en paralelo. En programas no triviales, el manejo de varios canales puede ser “convoluted”, como mostré en la implementación del algoritmo genético. Así que extendí el lenguaje para soporte objetos similares a agentes, en dirección a un &lt;a href="http://en.wikipedia.org/wiki/Actor_model" target="_blank"&gt;actor model&lt;/a&gt; parcial, con declaraciones como:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,,courier,monospace;font-size:12px;"&gt;agent MyAgent {
    &lt;span style="color:#008000;"&gt;// ....&lt;/span&gt;
}&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Una definición de agente es como la definición de una clase. Podemos crear agentes usando el operador new y constructores:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,,courier,monospace;font-size:12px;"&gt;agent = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; MyAgent(parameter);&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;La diferencia con un objeto es: cuando una instancia de agente es creada, se lanza un background thread para procesar una cola, donde se van guardando las llamadas a métodos del agente y sus parámetros. Esas llamadas son procesadas por el thread el propio agente. Un ejemplo:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,,courier,monospace;font-size:12px;"&gt;agent IncrementAgent 
{
  sub Process(channel, &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;)
  {
    channel &amp;lt;- &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt; + 1;
  }
}
myagent = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; IncrementAgent();
channel = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Channel();
myagent.Process(channel, 1);
result = &amp;lt;-channel; &lt;span style="color:#008000;"&gt;// result == 2&lt;/span&gt;
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;La llamada &lt;strong&gt;myagent.Process(..)&lt;/strong&gt; no se ejecuta en el thread principal, sino que es guardada en el queue interno del agente, y será procesada por el thread propio del agente. En la actual implementación, la queue interna es un queue channel, así que la sincronización entre invocadores y el agente es automática.&lt;/p&gt;

&lt;p&gt;Para implementar este tipo de agentes, agregué la clase &lt;strong&gt;AgentFunction&lt;/strong&gt;, representado el método a llamar. Cuando se lo invoca, no se ejecuta directamente sino que su invocación es enviada a la cola del agente:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; Invoke(IBindingEnvironment environment, &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt;[] arguments)
{
    AgentObject agent = (AgentObject)((ObjectEnvironment)environment).Object;
    agent.SendInvoke(&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.function, environment, arguments);
    &lt;span style="color:#008000;"&gt;// TODO if function, return a Future&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;null&lt;/span&gt;;
    &lt;span style="color:#008000;"&gt;// Old direct code&lt;/span&gt;
    &lt;span style="color:#008000;"&gt;//            return this.function.Invoke(environment, arguments);&lt;/span&gt;
}
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;La llamada &lt;strong&gt;SendInvoke&lt;/strong&gt; pone los datos de la invocación en la cola de proceso del agente.&lt;/p&gt;

&lt;p&gt;Hay una &lt;strong&gt;AgentClass&lt;/strong&gt;, derivada de &lt;strong&gt;DynamicClass&lt;/strong&gt; (que es la definición normal de una clase dinámica en AjSharp), extendida con una nueva manera de crear una instancia:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;override&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; NewInstance(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt;[] parameters)
{
    AgentObject dynobj = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; AgentObject(&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;);
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.NewInstance(dynobj, parameters);
    dynobj.Launch();
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; dynobj;
}
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;La clave está en &lt;strong&gt;dynobj.Launch()&lt;/strong&gt; que lanza el thread de proceso que ejecutará todas las llamadas al agente, tomando sus datos de la cola interna.&lt;/p&gt;

&lt;p&gt;De esta forma, llamar a un método de un agente recuerda a una message passing invocation. Si recordamos Smalltalk, una llamada es en realidad un mensaje con nombre y argumentos. En mi opinión, al usar la convención de &amp;lt;agente&amp;gt;.&amp;lt;método&amp;gt;(&amp;lt;parametros&amp;gt;) es una forma clara y transparente de implementar un message passing usando sintaxis “normal”.&lt;/p&gt;

&lt;p&gt;Esta es la actual implementación ingenua del agente:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; AgentObject : DynamicClassicObject
    {
        &lt;span style="color:#008000;"&gt;// TODO 100 is hard coded&lt;/span&gt;
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; QueueChannel channel = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; QueueChannel(100);
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; AgentObject(IClass objclass) 
            : &lt;span style="color:#0000ff;"&gt;base&lt;/span&gt;(objclass)
        {
        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; IChannel Channel { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt; { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.channel; } }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Launch()
        {
            Thread thread = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Thread(&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ParameterizedThreadStart(&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Execute));
            thread.IsBackground = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;
            thread.Start(Machine.Current);
        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; SendInvoke(ICallable function, IBindingEnvironment environment, &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt;[] arguments)
        {
            AgentTask task = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; AgentTask() { Callable = function, Environment = environment, Arguments = arguments };
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.channel.Send(task);
        }
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; Execute(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; parameter)
        {
            Machine machine = (Machine) parameter;
            machine.SetCurrent();
            &lt;span style="color:#0000ff;"&gt;while&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;)
            {
                &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; obj = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.channel.Receive();
                AgentTask task = (AgentTask) obj;
                task.Callable.Invoke(task.Environment, task.Arguments);
            }
        }
    }
    &lt;span style="color:#0000ff;"&gt;internal&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; AgentTask
    {
        &lt;span style="color:#0000ff;"&gt;internal&lt;/span&gt; ICallable Callable;
        &lt;span style="color:#0000ff;"&gt;internal&lt;/span&gt; IBindingEnvironment Environment;
        &lt;span style="color:#0000ff;"&gt;internal&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt;[] Arguments;
    }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Como siempre, el código está publicado en:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://code.google.com/p/ajcodekatas/source/browse/#svn/trunk/AjLanguage"&gt;http://code.google.com/p/ajcodekatas/source/browse/#svn/trunk/AjLanguage&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Próximos pasos:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Explorar el proceso de agente con un ejemplo. Podría portar el ejemplo de algoritmo genético que escribí en C# o anteriores ejemplos míos de web crawler. &lt;/li&gt;

  &lt;li&gt;Soportar la invocación de funciones que devuelvan valores en un agente: el resultado de retorono sería un future, que sería llenado por el agente en paralelo. Problemas: estaríamos en algún momento esperado el valor del future, con posibles dead-locks. &lt;/li&gt;

  &lt;li&gt;Algo más ambicioso: agentes distribuidos. Que el new o algo similar, provoque que el agente se ejecute en otra máquina, y nosotros lo manipulamos como siempre a través de un proxy. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nos leemos!&lt;/p&gt;

&lt;p&gt;Angel “Java” Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1757103" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx">AjSharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_F300_digo+Abierto/default.aspx">Proyectos de Código Abierto</category></item><item><title>Functional values en AjSharp</title><link>http://msmvps.com/blogs/lopez/archive/2010/02/06/functional_2D00_values_2D00_in_2D00_ajsharp.aspx</link><pubDate>Sat, 06 Feb 2010 14:21:49 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1755604</guid><dc:creator>lopez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1755604</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/02/06/functional_2D00_values_2D00_in_2D00_ajsharp.aspx#comments</comments><description>&lt;p&gt;Una de las características que quería tener desde el principio en mi intérprete &lt;a href="http://en.wordpress.com/tag/ajsharp/" target="_blank"&gt;AjSharp&lt;/a&gt; era que las funciones y rutinas sean ciudadanos de primera clase en el lenguaje (en este post uso la palabra clave &lt;strong&gt;function&lt;/strong&gt; pero se puede usar también &lt;strong&gt;sub&lt;/strong&gt; para definir una subrutina). &lt;/p&gt;  &lt;p&gt;El código está en el proyecto de código de Google:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://code.google.com/p/ajcodekatas/source/browse/#svn/trunk/AjLanguage"&gt;http://code.google.com/p/ajcodekatas/source/browse/#svn/trunk/AjLanguage&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;AjLanguage es el lenguaje núcleo (que no tiene ni parser ni lexer, sólo lo esencial del intérprete). AjSharp es el parser y el lexer implementado sobre el AjLanguage. De esta forma, podría implementar AjBasic u otros lenguajes similares, usando AjLanguage como base y núcleo.&lt;/p&gt;  &lt;p&gt;En AjSharp, podemos definir funciones como en otros lenguajes:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,,courier,monospace;font-size:12px;"&gt;function Square(n) { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; n*n; }&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Podemos definir una función anónimca y asignarla a una variable:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,,courier,monospace;font-size:12px;"&gt;MySquare = function (n) { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; n*n; };&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Un functional value puede ser usado como parámetro:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,,courier,monospace;font-size:12px;"&gt;function Apply(func,values)
{
  list = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; List();
  
  &lt;span style="color:#0000ff;"&gt;foreach&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;value&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;in&lt;/span&gt; values)
    list.Add(func(&lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;));
    
  &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; list;
}
numbers = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; List();
numbers.Add(1);
numbers.Add(2);
numbers.Add(3);
function Square(n) { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; n*n; }
squared = Apply(Square, numbers);
squared2 = Apply(function (n) { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; n*n; }, numbers);&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;La función Apply definida arriba, toma una función, una lista, y retorna otra lista de elementos que resultan de evaluar f(e), donde f es la función recibida, aplicada a cada elemento e de la lista que se pasó como parámetro. Podemos invocar Apply con el nombre de la función (que en realidad es el nombre de la variable que contiene al functional value) o definidiendo la función directamente en la invocación.&lt;/p&gt;

&lt;p&gt;Estoy pensando sobre algunas alternativas de implementación del alcance y visibilidad de variables en expresiones funcionales (dará para otro post el tema). Si definimos una función, AjLanguaje (el núcleo de AjSharp) usa una closure (clausura), así que cuando la función es invocada, el binding environment original es usado. En los ejemplos de más abajo se usa esa característica. &lt;/p&gt;

&lt;p&gt;Cada función implementa:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;interface&lt;/span&gt; ICallable
    {
        &lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; Arity { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt;; }
        IBindingEnvironment Environment { &lt;span style="color:#0000ff;"&gt;get&lt;/span&gt;; }
        &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; Invoke(IBindingEnvironment environment, &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt;[] arguments);
        &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; Invoke(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt;[] arguments);
    }&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;esto es, cuando es invocada, recibe un binding environment (un diccionario que dado el nombre de una variable nos da su valor asociado). Un funcional value no usa ese binding environment recibido, y lo reemplaza por el environment original que tenía en el momento de haber sido definida, creada.&lt;/p&gt;

&lt;p&gt;Podemos retornar una función como retorno de una función:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,,courier,monospace;font-size:12px;"&gt;function MakeIncrement(x) 
{
  &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; function(n) { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; n + x; }; &lt;span style="color:#008000;"&gt;// x is bounded to local parameter&lt;/span&gt;
}
Increment2 = MakeIncrement(2);
result = Increment2(2);
&lt;span style="color:#008000;"&gt;// result == 4&lt;/span&gt;
Increment3 = MakeIncrement(3);
result2 = Increment3(2);
&lt;span style="color:#008000;"&gt;// result2 == 5&lt;/span&gt;
result3 = MakeIncrement(4)(3);
&lt;span style="color:#008000;"&gt;// result3 == 7&lt;/span&gt;
x = 4;
result4 = function(n) { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; n+x; }(5);
&lt;span style="color:#008000;"&gt;// result4 == 9&lt;/span&gt;
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;MakeIncrement retorna una función que usa y accede a la variable &lt;strong&gt;x&lt;/strong&gt;, ligada en el binding environment de llamada.&lt;/p&gt;

&lt;p&gt;En el último comando, la función es definida e invocada en el mismo comando.&lt;/p&gt;

&lt;p&gt;AjSharp tiene clases, y podemos definir funciones y rutinas como métodos:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Person
{
  var Name;
  var Age;
  
  function AddYears(years) 
  {
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Age = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Age + years;
  }
}
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Pero también podemos agregar funciones en cualquier momento:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,,courier,monospace;font-size:12px;"&gt;&lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Person
{
  var Name;
  var Age;
  
  function Person()
  {
    x = 100;
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.GetYears = function () { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Age; };
    &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.GetX = function() { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; x; };
  }
}
adam = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Person() { Name = &amp;quot;&lt;span style="color:#8b0000;"&gt;Adam&lt;/span&gt;&amp;quot;, Age = 800 };
result = adam.GetYears();
&lt;span style="color:#008000;"&gt;// result == 800&lt;/span&gt;
result2 = adam.GetX();
&lt;span style="color:#008000;"&gt;// result2 == 100&lt;/span&gt;
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;o agregar funciones/rutinas directamente a objetos:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,,courier,monospace;font-size:12px;"&gt;adam.AddYears = sub(n) { &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Age = &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Age + n; };&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Hace unas semanas, leí el post:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://blog.james-carr.org/2009/08/31/functional-programming-in-javascript/" target="_blank"&gt;Functional Programming in Javascript&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;de &lt;a href="http://blog.james-carr.org" target="_blank"&gt;James Carr&lt;/a&gt;, así que decidí probar las capacidades de AjSharp para manejar functional values adaptando algunos de esos ejemplos, como:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,,courier,monospace;font-size:12px;"&gt;function runningSum(start){  
  sum = start;  &lt;span style="color:#008000;"&gt;// you could use var sum, it&amp;#39;s local&lt;/span&gt;
  
  &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; function(a){  
    sum = sum + a;  &lt;span style="color:#008000;"&gt;// function access the &amp;quot;outer&amp;quot; sum&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; sum;
  };
}  
sum = runningSum(3);  &lt;span style="color:#008000;"&gt;// makes function&lt;/span&gt;
result = sum(2); &lt;span style="color:#008000;"&gt;// returns 5  &lt;/span&gt;
result2 = sum(10); &lt;span style="color:#008000;"&gt;// returns 15  &lt;/span&gt;
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Podemos usar directamente el parámetro como acumulador:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,,courier,monospace;font-size:12px;"&gt;function runningSum(start){  
  &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; function(a){  
    start = start + a;  &lt;span style="color:#008000;"&gt;// function access the &amp;quot;outer&amp;quot; start&lt;/span&gt;
    &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; start;
  };
}  
sum = runningSum(3);  &lt;span style="color:#008000;"&gt;// makes function&lt;/span&gt;
result = sum(2); &lt;span style="color:#008000;"&gt;// returns 5  &lt;/span&gt;
result2 = sum(10); &lt;span style="color:#008000;"&gt;// returns 15  &lt;/span&gt;&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Agregué soporto para aplicar una función como si fuera un método a un objeto, como en uno de los ejemplos de&amp;#160; Carr (este tipo de llamada es soportada en Javascript que tiene la clase Function):&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,,courier,monospace;font-size:12px;"&gt;person = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; { Name = &amp;quot;&lt;span style="color:#8b0000;"&gt;Adam&lt;/span&gt;&amp;quot;, Age = 800 };
GetAdjustedAge = function (x) { &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; x + &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.Age; };
result = GetAdjustedAge.Call(person, 10); &lt;span style="color:#008000;"&gt;// result == 810&lt;/span&gt;
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Próximos pasos: estabilizar el alcance de las varaibles y el acceso al environment global. Por ahora, me divertí bastante implementando valores funcionales&lt;/p&gt;

&lt;p&gt;Nos leemos!&lt;/p&gt;

&lt;p&gt;Angel “Java” Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1755604" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx">AjSharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_F300_digo+Abierto/default.aspx">Proyectos de Código Abierto</category></item><item><title>Queue Channels en AjSharp</title><link>http://msmvps.com/blogs/lopez/archive/2010/01/29/queue_2D00_channels_2D00_in_2D00_ajsharp.aspx</link><pubDate>Fri, 29 Jan 2010 10:47:17 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1754348</guid><dc:creator>lopez</dc:creator><slash:comments>1</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1754348</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/01/29/queue_2D00_channels_2D00_in_2D00_ajsharp.aspx#comments</comments><description>&lt;p&gt;Hace una semanas, implementé channels en mi intérprete &lt;a href="http://en.wordpress.com/tag/ajsharp/"&gt;AjSharp&lt;/a&gt;. Pueden leer sobre el tema en:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://ajlopez.wordpress.com/Channels%20and%20GoRoutines%20in%20AjSharp%20%28Part%201%29"&gt;Channels and GoRoutines in AjSharp (part 1)&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://ajlopez.wordpress.com/2009/12/30/channels-and-goroutines-in-ajsharp-part-2/"&gt;Channels and GoRoutines in AjSharp (part 2)&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2009/12/29/channels_2D00_and_2D00_goroutines_2D00_in_2D00_ajsharp_2D00_part_2D00_1.aspx"&gt;Canales y GoRoutines en AjSharp (Part 1)&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2009/12/31/channels_2D00_and_2D00_goroutines_2D00_in_2D00_ajsharp_2D00_part_2D00_2.aspx"&gt;Canales y GoRoutines en AjSharp (Part 2)&lt;/a&gt;&lt;/p&gt; Si uno lee el valor de un canal, y no hay valor disponible, el thread que está tratando de leer se bloquea hasta que el valor esté disponible. Esta es una manera de sincronizar consumidores y productores que operan sobre el canal. Pero algunas veces queremos poner un valor en un canal y continua, sin bloqueo. Para eso, agregué una “queue channel” (podría llamarla queued channel): pueden poner N valores en el canal sin bloqueo, porque se van guardando en una cola interna. El tamaño de la cola se determina en un parámetro en el constructor. La cola está limitada en tamaño para poder preservar sus capacidades de sincronizació.  &lt;p&gt;El nombre de la nueva clase es QueueChannel. Un test:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; CreateAndUseQueueChannelWithTenElements()
        {
            QueueChannel channel = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; QueueChannel(10);
            &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; k = 1; k &amp;lt;= 10; k++)
                channel.Send(k);
            &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; k = 1; k &amp;lt;= 10; k++)
                Assert.AreEqual(k, channel.Receive());
        }&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;El canal recibe 10 valores sin bloquearse. Si enviamos más valores, debemos usar otro thread:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;        [TestMethod]
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; CreateAndUseQueueChannelWithMoreEntriesThanSize()
        {
            QueueChannel channel = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; QueueChannel(10);
            Thread thread = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Thread(&lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ThreadStart(&lt;span style="color:#0000ff;"&gt;delegate&lt;/span&gt;()
            {
                &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; k = 1; k &amp;lt;= 20; k++)
                    channel.Send(k);
            }));
            thread.Start();
            &lt;span style="color:#0000ff;"&gt;for&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;int&lt;/span&gt; k = 1; k &amp;lt;= 20; k++)
                Assert.AreEqual(k, channel.Receive());
        }
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Para probarlo en un ejemplo, reescribí el ejemplo de números primos usando queue channels:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;numbers = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; QueueChannel(10);
running = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;
k = 1;
go &lt;span style="color:#0000ff;"&gt;while&lt;/span&gt;(running) { k++; numbers &amp;lt;- k; }
function filter(&lt;span style="color:#0000ff;"&gt;in&lt;/span&gt;, &lt;span style="color:#0000ff;"&gt;out&lt;/span&gt;, prime)
{
  &lt;span style="color:#0000ff;"&gt;while&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;) 
  {
    &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt; = &amp;lt;-&lt;span style="color:#0000ff;"&gt;in&lt;/span&gt;;
    &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;value&lt;/span&gt; % prime)
      &lt;span style="color:#0000ff;"&gt;out&lt;/span&gt; &amp;lt;- &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;;
  }
}
function makefilter(channel, number)
{
  newchannel = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; QueueChannel(10);
  go filter(channel, newchannel, number);
  &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; newchannel;
}
channel = numbers;
number = &amp;lt;-channel;
&lt;span style="color:#0000ff;"&gt;while&lt;/span&gt; (number &amp;lt; 1000) 
{
  PrintLine(&amp;quot;&lt;span style="color:#8b0000;"&gt;Prime &lt;/span&gt;&amp;quot; + number);
  
  channel = makefilter(channel, number);
  
  number = &amp;lt;-channel;
}
running = &lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;;
&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;El código está en mi Google code project:&lt;/p&gt;

&lt;p&gt;&lt;a href="http://code.google.com/p/ajcodekatas/source/browse/#svn/trunk/AjLanguage"&gt;http://code.google.com/p/ajcodekatas/source/browse/#svn/trunk/AjLanguage&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Mi motivación para un queue channel apareció en ejemplo de algoritmo genético en paralelo, que sufría de demasiados bloqueos. Veo que un buen algoritmo no necesitaría colas, pero si uno tiene muchos consumidores y productores, y un thread produce valores para ser colocados en más de un canal, podría pasar que al colocar el valor en el canal A, no lleguemos a entregar el valor en el canal B, por bloqueo en la primera operación. Una forma de evitar el bloqueo es usando el comando go:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;go channel &amp;lt;- newvalue;&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Pero me parece que es demasiado lanzar una goroutine solamente para alimentar un canal.&lt;/p&gt;

&lt;p&gt;Tendría que presentar el algoritmo genético en paralelo (que ya hace unos meses presenté), y escribir algunas ideas para implementar un actor model en AjSharp, y usar agentes distribuidos.&lt;/p&gt;

&lt;p&gt;Nos leemos!&lt;/p&gt;

&lt;p&gt;Angel “Java” Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1754348" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx">AjSharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_F300_digo+Abierto/default.aspx">Proyectos de Código Abierto</category></item><item><title>AjSharp: Implementando Futures</title><link>http://msmvps.com/blogs/lopez/archive/2010/01/28/ajsharp_2D00_implementing_2D00_futures.aspx</link><pubDate>Thu, 28 Jan 2010 10:57:40 GMT</pubDate><guid isPermaLink="false">d67277c4-116b-43f1-b688-e9ef184ea916:1754212</guid><dc:creator>lopez</dc:creator><slash:comments>0</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://msmvps.com/blogs/lopez/rsscomments.aspx?PostID=1754212</wfw:commentRss><comments>http://msmvps.com/blogs/lopez/archive/2010/01/28/ajsharp_2D00_implementing_2D00_futures.aspx#comments</comments><description>&lt;p&gt;Había implementado canales en mi intérprete &lt;a href="http://en.wordpress.com/tag/ajsharp/" target="_blank"&gt;AjSharp&lt;/a&gt;. Describí el trabajo y ejemplos en:&lt;/p&gt;  &lt;p&gt;&lt;a target="_blank"&gt;Channels and GoRoutines in AjSharp (part 1)&lt;/a&gt;     &lt;br /&gt;&lt;a href="http://ajlopez.wordpress.com/2009/12/30/channels-and-goroutines-in-ajsharp-part-2/" target="_blank"&gt;Channels and GoRoutines in AjSharp (part 2)&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2009/12/29/channels_2D00_and_2D00_goroutines_2D00_in_2D00_ajsharp_2D00_part_2D00_1.aspx"&gt;Canales y GoRoutines en AjSharp (Part 1)&lt;/a&gt;    &lt;br /&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2009/12/31/channels_2D00_and_2D00_goroutines_2D00_in_2D00_ajsharp_2D00_part_2D00_2.aspx"&gt;Canales y GoRoutines en AjSharp (Part 2)&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;También los usé directamente en C#:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://msmvps.com/blogs/lopez/archive/2010/01/03/goroutines_2D00_and_2D00_channels_2D00_in_2D00_c.aspx" target="_blank"&gt;GoRoutines y Canales en C#&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;Podría usar canales para implementar &lt;a href="http://en.wikipedia.org/wiki/Futures_and_promises" target="_blank"&gt;futures&lt;/a&gt;. Una opción es usar &lt;a href="http://msdn.microsoft.com/en-us/library/dd460717%28VS.100%29.aspx" target="_blank"&gt;Task Parallel Library&lt;/a&gt; de Microsoft, pero entonces debería usar .NET 4: aparentemente, la librería original no está más disponible para .NET 3.x. Imagino que podría aprovecharme de las nuevas clases del nuevo framework, pero mientras, quiero explorar las ideas de programación con futures por mi cuenta.&lt;/p&gt;  &lt;p&gt;Los canales pueden ser usados para implementar el proceso de futures:&lt;/p&gt;  &lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;channel = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Channel();
go channel &amp;lt;- SomeLengthlyCalculation();
&lt;span style="color:#008000;"&gt;// .. more process&lt;/span&gt;
result = &amp;lt;- channel;&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;Pero los canales han sido diseñados para resolver otros problemas: para tener varios valores durante su vida, y ser usados como objetos de sincronización entre productores y consumidores de esos valores. La variable channel del ejemplo de arriba, si se usara como un future, podría ser consultada sólo una vez. Es un pequeño problema, pero señala una diferencia entre canales y futures.&lt;/p&gt;

&lt;p&gt;Así, escribí una nueva clase nativa, accesible desde programas AjSharp, llamada Future:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;    &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;class&lt;/span&gt; Future : IReference
    {
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;;
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; ManualResetEvent handle = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; ManualResetEvent(&lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;);
        &lt;span style="color:#0000ff;"&gt;private&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;bool&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;set&lt;/span&gt; = &lt;span style="color:#0000ff;"&gt;false&lt;/span&gt;;
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;void&lt;/span&gt; SetValue(&lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;)
        {
            &lt;span style="color:#0000ff;"&gt;lock&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;)
            {
                &lt;span style="color:#0000ff;"&gt;if&lt;/span&gt; (&lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.&lt;span style="color:#0000ff;"&gt;set&lt;/span&gt;)
                    &lt;span style="color:#0000ff;"&gt;throw&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; InvalidOperationException(&amp;quot;&lt;span style="color:#8b0000;"&gt;Future value already calculated&lt;/span&gt;&amp;quot;);
                &lt;span style="color:#0000ff;"&gt;set&lt;/span&gt; = &lt;span style="color:#0000ff;"&gt;true&lt;/span&gt;;
                &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.&lt;span style="color:#0000ff;"&gt;value&lt;/span&gt; = &lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;;
                &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.handle.Set();
            }
        }
        &lt;span style="color:#0000ff;"&gt;public&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;object&lt;/span&gt; GetValue()
        {
            &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.handle.WaitOne();
            &lt;span style="color:#0000ff;"&gt;return&lt;/span&gt; &lt;span style="color:#0000ff;"&gt;this&lt;/span&gt;.&lt;span style="color:#0000ff;"&gt;value&lt;/span&gt;;
        }
    }&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;En la versión actual en el trunk, la interface IReference (que contiene méteodos SetValue, GetValue) está implementada por la clase Channel. Los operadores AjSharp a &amp;lt;- b, a = &amp;lt;-b, son mapeados a esos métodos. Entonces podemos usar Futures de esta forma:&lt;/p&gt;

&lt;pre&gt;&lt;pre style="background-color:#ffffff;margin:0em;width:100%;font-family:consolas,courier,monospace;font-size:12px;"&gt;future = &lt;span style="color:#0000ff;"&gt;new&lt;/span&gt; Future();
go future &amp;lt;- SomeLenghtlyProcess();
&lt;span style="color:#008000;"&gt;// ... more process&lt;/span&gt;
result = &amp;lt;-future;
result2 = &amp;lt;-future;&lt;/pre&gt;&lt;/pre&gt;

&lt;p&gt;La consulta del valor del future es explícita, usando el operador &amp;lt;-. De esta forma, podemos pasar la variable future a cualquier otra función, usando el nombre, sin ver todavía su valor. Podría eliminar el go en el seteo de la variable future, asumiendo que el valor a la derecha de ese valor se calcula en paralelo. Pero prefiero hacer que el paralelismo quede explícito, usando el comando go.&lt;/p&gt;

&lt;p&gt;Esta es una mejora menor en el procesamiento en paralelo de AjSharp. Estoy trabajando en queue channels: channels que soporten el manejo de más de un valor, sin bloquearse. Pueden ver el código y ejemplos en:&lt;/p&gt;

&lt;p&gt;&lt;a title="http://code.google.com/p/ajcodekatas/source/browse/#svn/trunk/AjLanguage" href="http://code.google.com/p/ajcodekatas/source/browse/#svn/trunk/AjLanguage"&gt;http://code.google.com/p/ajcodekatas/source/browse/#svn/trunk/AjLanguage&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quiero implementar agentes, para soportar la programación basada en el actor model. Podría ser interesante tener a la palabra agent como palabra clave, como la palabra class. Y que esos agentes puedan ser ejecutados en máquinas remotas.&lt;/p&gt;

&lt;p&gt;Nos leemos!&lt;/p&gt;

&lt;p&gt;Angel “Java” Lopez 
  &lt;br /&gt;&lt;a href="http://www.ajlopez.com"&gt;http://www.ajlopez.com&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://twitter.com/ajlopez"&gt;http://twitter.com/ajlopez&lt;/a&gt;&lt;/p&gt;&lt;div style="clear:both;"&gt;&lt;/div&gt;&lt;img src="http://msmvps.com/aggbug.aspx?PostID=1754212" width="1" height="1"&gt;</description><category domain="http://msmvps.com/blogs/lopez/archive/tags/.NET/default.aspx">.NET</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Lenguajes+de+Programaci_26002300_243_3B00_n/default.aspx">Lenguajes de Programaci&amp;#243;n</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/AjSharp/default.aspx">AjSharp</category><category domain="http://msmvps.com/blogs/lopez/archive/tags/Proyectos+de+C_F300_digo+Abierto/default.aspx">Proyectos de Código Abierto</category></item></channel></rss>