<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Jaros&#322;aw Zabie&#322;&#322;o - BLOG: Tag java</title>
    <link>http://blog.zabiello.com/articles/tag/java</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>moje notatki, linki, komentarze</description>
    <item>
      <title>JRuby - metoda initialize i Java</title>
      <description>&lt;p&gt;Ostatnio, podczas pr&#243;by u&#380;ycia &lt;a href="http://www.whalin.com/memcached/"&gt;javowej biblioteki&lt;/a&gt; w JRuby spotka&#322;em problem z kolizj&#261; nazw metod Javy z metodami Rubiego. Mianowicie chodzi o metod&#281; o nazwie &lt;code&gt;initialize&lt;/code&gt; jaka by&#322;a zdefiniowana w bibliotece Javy. W JRuby (i Ruby) nazwa ta jest zarezerwowana dla konstruktora. Dzi&#281;ki temu, &#380;e mia&#322;em dost&#281;p do &#378;r&#243;de&#322; w Javie, m&#243;g&#322;bym po prostu je zmodyfikowa&#263;. Jednak&#380;e, takie podej&#347;cie nie za bardzo mi si&#281; podoba&#322;o. Co w wypadku kiedy mia&#322;bym bibliotek&#281; dost&#281;pn&#261; tylko w postaci skompilowanych klas?&lt;/p&gt;


	&lt;p&gt;Przeczesuj&#261;c internet, nie znalaz&#322;em nic na ten temat. W bugtrackerze JRuby mo&#380;na znale&#378;&#263; dwa tickety (&lt;a href="http://jira.codehaus.org/browse/JRUBY-45"&gt;45&lt;/a&gt;  i &lt;a href="http://jira.codehaus.org/browse/JRUBY-2799"&gt;2799&lt;/a&gt;) kt&#243;re wspominaj&#261; o tym problemie, lecz nie dostarczaj&#261; &#380;adnego rozwi&#261;zania. W tym drugim podano niby obej&#347;cie problemu, tylko &#380;e b&#322;&#281;dne (dopisalem tam swoj&#261; uwag&#281;). Poprawne rozwi&#261;zanie otrzyma&#322;em od Marcina Miel&#380;y&#324;skiego (developera JRuby) na grupie pl.comp.lang.ruby.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_java "&gt;package pl.foo.bar;
public class X {
    public void initialize() {
        System.out.println(&amp;quot;foo&amp;quot;);
    }
}

include Java
require 'X.jar'

X = Java::PlFooBar::X
jcls = X.java_class
m = jcls.declared_method(&amp;quot;initialize&amp;quot;)
m.invoke(X.new.java_object)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Zainspirowany tym podej&#347;ciem postanowi&#322;em napisa&#263; bardziej og&#243;lne rozwi&#261;zanie tego typu problem&#243;w.&lt;/p&gt;


	&lt;p&gt;W komentarzach do ticketu &lt;a href="http://jira.codehaus.org/browse/JRUBY-2799"&gt;2799&lt;/a&gt; pad&#322;a sugestia, aby stworzy&#263; dodatkow&#261; metod&#281; &lt;code&gt;java_call&lt;/code&gt; o sugerowanej, nast&#281;puj&#261;cej sk&#322;adni:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;result&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;my_inst&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;java_call&lt;/span&gt; &lt;span class="symbol"&gt;:my_method&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;an arg or&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="number"&gt;2&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Niestety, taki pomy&#347;l raczej nie wypali z powodu specyfiki Javy. W przeciwie&#324;stwie do Rubiego, Java nie u&#380;ywa unikalnych nazw metod, ale stosuje ich przeci&#261;&#380;anie. Java rozr&#243;&#380;nia tak&#380;e typy prymitywne int, float, boolean od obiekt&#243;w Integer, Float czy Boolean. Mimo, &#380;e te drugie s&#261; co prawda wrapperami dla prymityw&#243;w, je&#347;li jaka&#347; biblioteka Javy posiada dwie metody o tej samej nazwie ale r&#243;&#380;ni&#261;ce si&#281; typem int vs. Integer, to JRuby nie za bardzo b&#281;dzie wiedzie&#263; kt&#243;r&#261; metod&#281; ma wybra&#263; (w Ruby nie ma prymityw&#243;w, wszystko jest obiektem na tych samych prawach). Np. za&#322;&#243;&#380;my, &#380;e mamy bibliotek&#281; o takim kodzie:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_java "&gt;public class Tescior {
    public void initialize() {
        System.out.println(&amp;quot;initialize is reserved for constructor in JRuby&amp;quot;);
    }
    public void initialize(String name) {
        System.out.println(&amp;quot;Hello &amp;quot; + name);
    }
    public void initialize(Integer x, Integer y) {
        System.out.printf(&amp;quot;%s + %s = %s\n&amp;quot;, x,y,(x+y));
    }
    public void initialize(int x, Integer y) {
        System.out.printf(&amp;quot;%s + %s = %s\n&amp;quot;, x,y,(x+y));
    }
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Jak niby sk&#322;adnia &lt;code&gt;my_inst.java_call(:initialize, 3, 4)&lt;/code&gt; ma wiedzie&#263; czy chodzi o powy&#380;sz&#261; metod&#281; 3, czy 4? Nie da si&#281;! Aby to obej&#347;&#263;, nale&#380;y przekazywa&#263; nazwy typ&#243;w. Dopiero gdy znamy nazw&#281; metody i typy jej argument&#243;w mo&#380;emy jednoznacznie w Javie okre&#347;li&#263; o jak&#261; metod&#281; nam chodzi.&lt;/p&gt;


	&lt;p&gt;Skompilujmy z konsoli powy&#380;szy kod Javy i stw&#243;rzmy jar&amp;#8217;a.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;$ javac Tescior.java
$ zip Tescior.jar Tescior.class&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Kod JRuby i przyk&#322;ad u&#380;ycia:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;include&lt;/span&gt; &lt;span class="constant"&gt;Java&lt;/span&gt;

&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Tescior.jar&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;
&lt;span class="ident"&gt;include_class&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Tescior&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Java::JavaLang::Object&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;java_call&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;method_name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;jcls&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;java_class&lt;/span&gt;
    &lt;span class="ident"&gt;m&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;jcls&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;declared_method&lt;/span&gt; &lt;span class="ident"&gt;method_name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;]}&lt;/span&gt;
    &lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;invoke&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;java_object&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="constant"&gt;Java&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;ruby_to_java&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;])}&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="comment"&gt;# test&lt;/span&gt;
&lt;span class="constant"&gt;Tescior&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;java_call&lt;/span&gt; &lt;span class="symbol"&gt;:initialize&lt;/span&gt;
&lt;span class="constant"&gt;Tescior&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;java_call&lt;/span&gt; &lt;span class="symbol"&gt;:initialize&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;java&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;lang&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;String&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Jarek!&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;]&lt;/span&gt;
&lt;span class="ident"&gt;Tescior&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;java_call&lt;/span&gt; &lt;span class="symbol"&gt;:initialize&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:int&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;3&lt;/span&gt;&lt;span class="punct"&gt;],&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;java&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;lang&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Integer&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;4&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;
&lt;span class="ident"&gt;Tescior&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;java_call&lt;/span&gt; &lt;span class="symbol"&gt;:initialize&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;java&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;lang&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Integer&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;6&lt;/span&gt;&lt;span class="punct"&gt;],&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;java&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;lang&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;Integer&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;7&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Jak wida&#263;, przekazywane s&#261; typy i warto&#347;ci parametr&#243;w. JRuby wszystkie typy prymitywne przekazuje za pomoc&#261; symboli. Pozosta&#322;e s&#261; przekazywane przez &lt;code&gt;java.lang&lt;/code&gt; i s&#261; zgodne z &lt;a href="http://java.sun.com/javase/6/docs/api/"&gt;javowym &lt;span class="caps"&gt;API&lt;/span&gt;&lt;/a&gt;. Powy&#380;szy kod mo&#380;na troszk&#281; upro&#347;ci&#263;. Po co pisa&#263; takie d&#322;ugie deklaracje, skoro mo&#380;na pro&#347;ciej wiedz&#261;c &#380;e wszystkie nazwy klas Javy zaczynaj&#261; si&#281; z du&#380;ej litery. Mimo, &#380;e to nie jest wym&#243;g j&#281;zyka (tak jak jest to w Ruby) ta konwencja jest konsekwentnie stosowana i to wystarczy.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Java::JavaLang::Object&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;java_call&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;method_name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;jcls&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;java_class&lt;/span&gt;
    &lt;span class="ident"&gt;m&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;jcls&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;declared_method&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;method_name&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;map&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
      &lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt; &lt;span class="punct"&gt;=~&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt;&lt;span class="regex"&gt;^[A-Z]&lt;/span&gt;&lt;span class="punct"&gt;/&lt;/span&gt; &lt;span class="punct"&gt;?&lt;/span&gt; &lt;span class="ident"&gt;eval&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;java.lang.&lt;span class="expr"&gt;#{x[0]}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;):&lt;/span&gt; &lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;invoke&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;java_object&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;params&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;map&lt;/span&gt;&lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="constant"&gt;Java&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;ruby_to_java&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;])}&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="comment"&gt;# test:&lt;/span&gt;
&lt;span class="constant"&gt;Tescior&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;java_call&lt;/span&gt; &lt;span class="symbol"&gt;:initialize&lt;/span&gt;
&lt;span class="constant"&gt;Tescior&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;java_call&lt;/span&gt; &lt;span class="symbol"&gt;:initialize&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:String&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;World!&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;]&lt;/span&gt;
&lt;span class="constant"&gt;Tescior&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;java_call&lt;/span&gt; &lt;span class="symbol"&gt;:initialize&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:int&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;7&lt;/span&gt;&lt;span class="punct"&gt;],&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:Integer&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;8&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;
&lt;span class="constant"&gt;Tescior&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;java_call&lt;/span&gt; &lt;span class="symbol"&gt;:initialize&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:Integer&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;9&lt;/span&gt;&lt;span class="punct"&gt;],&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="symbol"&gt;:Integer&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="number"&gt;10&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Ten zapis jest ju&#380; du&#380;o lepszy i zgodny z filozofi&#261; Javy. Aby wiedzie&#263; o jak&#261; metod&#281; chodzi, potrzebna jest nie tylko jej nazwa ale i typy jej parametr&#243;w formalnych. Prawd&#281; m&#243;wi&#261;c, dzi&#281;ki JRuby zaczynam nawet lubi&#263; Jav&#281;. Dost&#281;p do pot&#281;&#380;nych bibliotek ale w ludzki, przyjazny spos&#243;b.&lt;/p&gt;</description>
      <pubDate>Thu, 14 Aug 2008 04:38:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:87921ad5-2609-4163-82d1-b4dd8b25d837</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/08/14/jruby-initialize-problem</link>
      <category>jruby</category>
      <category>java</category>
    </item>
    <item>
      <title>Ruby, Python i natywne w&#261;tki systemu operacyjnego</title>
      <description>&lt;p&gt;Wiele si&#281; m&#243;wi o tym, &#380;e Ruby jak i Python nie posiadaj&#261; obs&#322;ugi natywnych w&#261;tk&#243;w systemu operacyjnego. Wbudowane, tzw. &lt;em&gt;green threads&lt;/em&gt;, nie s&#261; w stanie wykorzysta&#263; zalet maszyn wyposa&#380;onych w procesory wielordzeniowe. Istniej&#261; jednak implementacje obu j&#281;zyk&#243;w w czystej Javie. Czy ich u&#380;ycie daje jakie&#347; znacz&#261;ce przy&#347;pieszenie?&lt;/p&gt;


	&lt;p&gt;Wszystkie testy by&#322;y wykonywane na MacBook Pro Core2 Duo 2.16GHZ, 4GB &lt;span class="caps"&gt;RAM&lt;/span&gt; i systemie Mac &lt;span class="caps"&gt;OS X 10&lt;/span&gt;.5.4 Leopard + zainstalowana Java 1.6.0_05.&lt;/p&gt;


	&lt;h2&gt;Python&lt;/h2&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;time&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;time&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;random&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="constant"&gt;Random&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;threading&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="constant"&gt;Thread&lt;/span&gt;
&lt;span class="ident"&gt;rand&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Random&lt;/span&gt;&lt;span class="punct"&gt;().&lt;/span&gt;&lt;span class="ident"&gt;randint&lt;/span&gt; &lt;span class="comment"&gt;# alias&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Test(Thread):&lt;/span&gt;
   &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;__init__&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt; 
      &lt;span class="constant"&gt;Thread&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;__init__&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
      &lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Starting %s&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;getName&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
   &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;run&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt; 
      &lt;span class="ident"&gt;a&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;rand&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="constant"&gt;SIZE&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;for&lt;/span&gt; &lt;span class="ident"&gt;x&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="ident"&gt;xrange&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;SIZE&lt;/span&gt;&lt;span class="punct"&gt;)]&lt;/span&gt;
      &lt;span class="ident"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;sort&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
      &lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;%s finished&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;getName&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;      

&lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Start&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="ident"&gt;start&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;time&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
&lt;span class="constant"&gt;THREADS&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;SIZE&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;20&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;100000&lt;/span&gt;
&lt;span class="ident"&gt;threads&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[]&lt;/span&gt;             
&lt;span class="keyword"&gt;for&lt;/span&gt; &lt;span class="ident"&gt;i&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="ident"&gt;xrange&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;THREADS&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;
    &lt;span class="ident"&gt;t&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Test&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
    &lt;span class="ident"&gt;threads&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;append&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;start&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;     
&lt;span class="keyword"&gt;while&lt;/span&gt; &lt;span class="constant"&gt;True&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;isAlive&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt; &lt;span class="keyword"&gt;for&lt;/span&gt; &lt;span class="ident"&gt;t&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="ident"&gt;threads&lt;/span&gt;&lt;span class="punct"&gt;]:&lt;/span&gt;
    &lt;span class="ident"&gt;pass&lt;/span&gt;
&lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Time: %s s&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;time&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt; &lt;span class="punct"&gt;-&lt;/span&gt; &lt;span class="ident"&gt;start&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Dla powy&#380;szego kodu Python i Jython uzyska&#322;y wyniki:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Jython 2.2.1 = 12.15 s.&lt;/li&gt;
		&lt;li&gt;Python 2.5.2 = 14.24 s.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Ro&#380;nica jako&#347; podejrzanie ma&#322;a wskazuj&#261;ca na wci&#261;&#380; jeszcze niedojrza&#322;&#261; implementacj&#281; Jythona. Dla pewno&#347;ci, zmodyfikowa&#322;em kod tak, aby korzysta&#322; z natywnych bibliotek Javy.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;time&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;time&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;random&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="constant"&gt;Random&lt;/span&gt;
&lt;span class="ident"&gt;rand&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Random&lt;/span&gt;&lt;span class="punct"&gt;().&lt;/span&gt;&lt;span class="ident"&gt;randint&lt;/span&gt; &lt;span class="comment"&gt;# alias&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;java&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;lang&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="constant"&gt;Thread&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;Runnable&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Test(Runnable):&lt;/span&gt;
   &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;__init__&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt; 
      &lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Starting %s&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;
   &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;run&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;         
      &lt;span class="ident"&gt;a&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;rand&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="constant"&gt;SIZE&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;for&lt;/span&gt; &lt;span class="ident"&gt;x&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="ident"&gt;xrange&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;SIZE&lt;/span&gt;&lt;span class="punct"&gt;)]&lt;/span&gt;
      &lt;span class="ident"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;sort&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;  
      &lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;%s finished&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;

&lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Start&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="ident"&gt;start&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;time&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
&lt;span class="constant"&gt;THREADS&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;SIZE&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;20&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;100000&lt;/span&gt;    
&lt;span class="ident"&gt;threads&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[]&lt;/span&gt;             
&lt;span class="keyword"&gt;for&lt;/span&gt; &lt;span class="ident"&gt;i&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="ident"&gt;xrange&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;THREADS&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;
    &lt;span class="ident"&gt;t&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Thread&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;Test&lt;/span&gt;&lt;span class="punct"&gt;())&lt;/span&gt;              
    &lt;span class="ident"&gt;threads&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;append&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;start&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;     
&lt;span class="keyword"&gt;while&lt;/span&gt; &lt;span class="constant"&gt;True&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;isAlive&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt; &lt;span class="keyword"&gt;for&lt;/span&gt; &lt;span class="ident"&gt;t&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="ident"&gt;threads&lt;/span&gt;&lt;span class="punct"&gt;]:&lt;/span&gt;
    &lt;span class="ident"&gt;pass&lt;/span&gt;
&lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Time: %s s&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;time&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt; &lt;span class="punct"&gt;-&lt;/span&gt; &lt;span class="ident"&gt;start&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Tym razem&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Jython 2.2.1 = 11.96 s.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;R&#243;&#380;nica jest minimalna. Na dodatek panuje troch&#281; zamieszania co do sposobu odpalania w&#261;tk&#243;w w Jythonie &amp;#8211; &lt;a href="http://aspn.activestate.com/ASPN/Mail/Message/Jython-users/2034708"&gt;m&#281;tna sk&#322;adnia i za du&#380;o mo&#380;liwych sposob&#243;w&lt;/a&gt; uzyskania tego samego efektu. Po SQLAlchemy, Jython jest kolejnym przyk&#322;adam ca&#322;kowitej ignorancji za&#322;o&#380;e&#324; j&#281;zyka Python (o istnieniu jednej, oczywistej drogi do tego samego celu). Na domiar z&#322;ego, m&#243;j pierwotny test zak&#322;ada&#322; testowanie miliona liczb do sortowania. Jython nie by&#322; w stanie tego testu wykona&#263; z powodu braku pami&#281;ci dla Javy. Ruszy&#322; dopiero jak mu zaalokowa&#322;em 1GB (s&#322;ownie: jeden gigabajt pami&#281;ci) za pomoc&#261; opcji (-Xmx1024M), co jest po prostu chore! Po wymianie pierwotnego &lt;code&gt;range()&lt;/code&gt; na generatorowy &lt;code&gt;xrange()&lt;/code&gt; zapotrzebowanie na pami&#281;&#263; wyra&#378;nie zmala&#322;o i wystarczy&#322;a ju&#380; opcja -Xmx256M. Jednak&#380;e kod si&#281; wykonywa&#322;&#160;tak koszmarnie wolno, &#380;e nie starczy&#322;o mi cierpliwo&#347;ci i zmniejszy&#322;em ilo&#347;&#263; iteracji do 100 tys.&lt;/p&gt;


	&lt;h2&gt;Ruby&lt;/h2&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;time&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;thread&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;

&lt;span class="constant"&gt;THREADS&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;SIZE&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;20&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;100_000&lt;/span&gt;

&lt;span class="ident"&gt;start&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Start&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="ident"&gt;threads&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;..&lt;/span&gt;&lt;span class="constant"&gt;THREADS&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;map&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;i&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
  &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Starting Thread-&lt;span class="expr"&gt;#{i}&lt;/span&gt;&lt;span class="escape"&gt;\n&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="constant"&gt;Thread&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;i&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
    &lt;span class="ident"&gt;a&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;..&lt;/span&gt;&lt;span class="constant"&gt;SIZE&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;map&lt;/span&gt; &lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;e&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;rand&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;SIZE&lt;/span&gt;&lt;span class="punct"&gt;)}&lt;/span&gt;
    &lt;span class="ident"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;sort!&lt;/span&gt;
    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Thread-&lt;span class="expr"&gt;#{t}&lt;/span&gt; ended&lt;span class="escape"&gt;\n&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;while&lt;/span&gt; &lt;span class="ident"&gt;t&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;threads&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;find&lt;/span&gt; &lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;lt&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;lt&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;alive?&lt;/span&gt;&lt;span class="punct"&gt;}&lt;/span&gt;
  &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;join&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt; 
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Time: &lt;span class="expr"&gt;#{Time.now - start}&lt;/span&gt; s.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Pierwsze, co mi si&#281; od razu rzuca w oczy, to o wiele czytelniejsza, zgrzebniejsza sk&#322;adnia Rubiego, kt&#243;ry tu korzysta z blok&#243;w kodu. Po drugie, wyniki s&#261; dosy&#263; ciekawe:&lt;/p&gt;


	&lt;ul&gt;
	&lt;li&gt;Ruby 1.9.0 = 1.11 s&lt;/li&gt;
		&lt;li&gt;Ruby Enterprise = 2.77 s&lt;/li&gt;
		&lt;li&gt;JRuby 1.1.2 = 3.53 s&lt;/li&gt;
		&lt;li&gt;Ruby 1.8.7 = 21.82 s.&lt;/li&gt;
	&lt;/ul&gt;


	&lt;p&gt;Ruby okaza&#322; si&#281; najwolniejszy w tym zestawieniu. Python by&#322; tylko troch&#281; szybszy. JRuby, korzystaj&#261;cy z javowych w&#261;tk&#243;w systemowych, zdeklasowa&#322; Rubiego, Pythona i niedojrza&#322;ego Jythona. Jednak&#380;e to nie JRuby okaza&#322; si&#281; tu zwyci&#281;zc&#261;. Nie trzeba czeka&#263; na Ruby 2.0, wersja 1.9 posiada ju&#380; natywn&#261; obs&#322;ug&#281; w&#261;tk&#243;w &lt;span class="caps"&gt;POSIX&lt;/span&gt; i jest dodatkowo nie&#378;le zoptymalizowana. Ruby 1.9 pokaza&#322;, &#380;e jest tu prawie 4x szybszy od JRuby. Nie s&#261;dz&#281;, &#380;e t&#261; szybko&#347;&#263; uzyska&#322; na lepszej implementacji w&#261;tk&#243;w od Javy. Raczej ma mocno zoptymalizowany kod kt&#243;ry by&#322; wykonywany w ka&#380;dym z w&#261;tk&#243;w.&lt;/p&gt;


	&lt;p&gt;Bardzo dobrze poradzi&#322; sobie te&#380; &lt;a href="http://www.rubyenterpriseedition.com/"&gt;Ruby Enterprise&lt;/a&gt;, zoptymalizowana wersja Ruby 1.8.6 przez tw&#243;rc&#243;w &lt;a href="http://www.modrails.com/"&gt;Passengera&lt;/a&gt;! Nie wiem jakim cudem Ruby Enterprise pobi&#322;&#160;JRubiego&amp;#8230; no chyba, &#380;e jego tw&#243;rcy dodali mu obs&#322;ug&#281; natywnych w&#261;tk&#243;w systemu operacyjnego. Inaczej nie mog&#281; sobie wyt&#322;umaczy&#263; tak dobrego wyniku.&lt;/p&gt;


	&lt;h2&gt;Updated&lt;/h2&gt;


	&lt;p&gt;Dla pe&#322;niejszego obrazu uruchomi&#322;em testy dla 1 w&#261;tku. Poprawi&#322;em te&#380; b&#322;&#261;d z ilo&#347;ci&#261; list do sortowania faworyzuj&#261;c&#261; Rubiego. Ostateczne podsumowanie wygl&#261;da tak:&lt;/p&gt;


	&lt;p&gt;1 thread, 2,000,000 iterations&lt;/p&gt;


	&lt;ol&gt;
	&lt;li&gt;Ruby 1.9 = 1.69 s.   &lt;/li&gt;
		&lt;li&gt;Ruby Enterprise = 3.38 s.&lt;/li&gt;
		&lt;li&gt;JRuby 1.1.2 = 7.06 s.&lt;/li&gt;
		&lt;li&gt;Jython 2.2.1 = 17.29 s.&lt;/li&gt;
		&lt;li&gt;Python 2.5.2 = 18.06 s.&lt;/li&gt;
		&lt;li&gt;Ruby 1.8.7 = 22.37 s.&lt;/li&gt;
	&lt;/ol&gt;


	&lt;p&gt;20 threads * 100,000 iterations&lt;/p&gt;


	&lt;ol&gt;
	&lt;li&gt;Ruby 1.9 = 1.54 s.   &lt;/li&gt;
		&lt;li&gt;Ruby Enterprise = 3.01 s.           &lt;/li&gt;
		&lt;li&gt;JRuby 1.1.2 = 5.82 s.&lt;/li&gt;
		&lt;li&gt;Jython 2.2.1 = 11.86 s.&lt;/li&gt;
		&lt;li&gt;Python 2.5.2 = 12.32 s.                                                  &lt;/li&gt;
		&lt;li&gt;Ruby 1.8.7 = 22.68 s.&lt;/li&gt;
	&lt;/ol&gt;


	&lt;p&gt;Czasy, kiedy Python by&#322;&#160;zawsze szybszy od Rubiego, to ju&#380; przesz&#322;o&#347;&#263;. Z wynik&#243;w wynika, &#380;e to nie obs&#322;uga w&#261;tk&#243;w zadecydowa&#322;a o wynikach. Ruby 1.9 pobi&#322;&#160;wszystkich zar&#243;wno w te&#347;cie 1 jak i wielu w&#261;tk&#243;w.&lt;/p&gt;


	&lt;h2&gt;Updated 2008-07-30&lt;/h2&gt;


	&lt;p&gt;Poprawi&#322;em troch&#281; test, aby nie zu&#380;ywa&#322; tyle pami&#281;ci. Wyrzuci&#322;em wi&#281;c generowanie list i sortownie. Zosta&#322;o samo generowanie losowych liczb. Doda&#322;em te&#380; kod dla Javy dla por&#243;wnania.&lt;/p&gt;


	&lt;h3&gt;Java&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_java "&gt;import java.util.Random;

public class Main {

  static Integer SIZE,  ITERATIONS;

  public static void main(String[] args) throws Exception {
    Integer[] threads_nr = {1, 10, 50, 100};
    SIZE = Integer.parseInt(args[1]);
    System.out.println(args[0]);
    for(Integer nr: threads_nr) {
      ITERATIONS = SIZE / nr;
      System.out.printf(&amp;quot; %3d thread(s) x %9s = &amp;quot;, nr, ITERATIONS);
      long start = System.currentTimeMillis();
      Thread[] threads = new Thread[nr];
      for(int i = 0; i &amp;lt; threads.length; i++) {
        threads[i] = new ThreadTest();
        threads[i].start();
      }
      while(threadsAlive(threads)) {}
      System.out.printf(&amp;quot;%s s.\n&amp;quot;, (System.currentTimeMillis() - start) / 1000.0);
    }
  }

  public static boolean threadsAlive(Thread[] threads) {
    for(Thread t: threads)
      if(t.isAlive())
        return true;
    return false;
  }

  static class ThreadTest extends Thread {

    @Override
    public void run() {
      Random rnd = new Random();
      for(int i = 0; i &amp;lt; ITERATIONS; i++)
        rnd.nextInt(SIZE);
    }
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Test:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;$ java Main &amp;quot;`java -version`&amp;quot; 10000000
java version &amp;quot;1.6.0_05&amp;quot;
Java(TM) SE Runtime Environment (build 1.6.0_05-b13-120)
Java HotSpot(TM) 64-Bit Server VM (build 1.6.0_05-b13-52, mixed mode)
  1 thread(s) x  10000000 = 0.361 s.
 10 thread(s) x   1000000 = 0.18 s.
 50 thread(s) x    200000 = 0.186 s.
100 thread(s) x    100000 = 0.189 s.  &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Java, co nie dziwi, jest najszybsza. Nie ma znacz&#261;cej r&#243;&#380;nicy mi&#281;dzy 10 czy 10 w&#261;tkami, bo m&#243;j procesor posiada tylko dwa rdzenie.&lt;/p&gt;


	&lt;h3&gt;Ruby/JRuby&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;time&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;thread&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;

&lt;span class="constant"&gt;SIZE&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ARGV&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;to_i&lt;/span&gt;  
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="constant"&gt;ARGV&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;   
&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;10&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;50&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;100&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;nr&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
  &lt;span class="ident"&gt;iterations&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;SIZE&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt; &lt;span class="ident"&gt;nr&lt;/span&gt;
  &lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt; %3d thread(s) x %9s = &lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;nr&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;iterations&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;
  &lt;span class="ident"&gt;start&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt;
  &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;..&lt;/span&gt;&lt;span class="ident"&gt;nr&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;map&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;i&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
    &lt;span class="constant"&gt;Thread&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;i&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
      &lt;span class="ident"&gt;iterations&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;times&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;span class="ident"&gt;rand&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;SIZE&lt;/span&gt;&lt;span class="punct"&gt;)}&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;join&lt;/span&gt;&lt;span class="punct"&gt;}&lt;/span&gt;
  &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="constant"&gt;Time&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;now&lt;/span&gt; &lt;span class="punct"&gt;-&lt;/span&gt; &lt;span class="ident"&gt;start&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Ten sam kod w Ruby/JRuby wygl&#261;da znacznie kr&#243;cej (i &#322;adniej) ale kosztem wydajno&#347;ci. To te&#380; nie dziwi. Ruby jest bardzo produktywnym j&#281;zykiem, lecz oczywi&#347;cie nie tak szybkim jak Java.&lt;/p&gt;


	&lt;p&gt;Wyniki test&#243;w:&lt;/p&gt;


	&lt;p&gt;Ruby 1.9:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;$ ruby1.9 main.rb &amp;quot;`ruby1.9 -v`&amp;quot; 10_000_000
ruby 1.9.0 (2008-06-20 revision 17482) [i686-darwin9.4.0]
  1 thread(s) x  10000000 = 2.858588
 10 thread(s) x   1000000 = 2.832928
 50 thread(s) x    200000 = 2.845377
100 thread(s) x    100000 = 2.852745&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;JRuby:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;$ jruby main.rb &amp;quot;`jruby -v`&amp;quot; 10_000_000
jruby 1.1.3 (ruby 1.8.6 patchlevel 114) (2008-07-28 rev 6586) [x86_64-java]
   1 thread(s) x  10000000 = 3.58
  10 thread(s) x   1000000 = 3.4290000000000003
  50 thread(s) x    200000 = 3.442
 100 thread(s) x    100000 = 3.516&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Ruby Enterprise:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;$ ruby-enterprise main.rb &amp;quot;`ruby-enterprise -v`&amp;quot; 10_000_000
ruby 1.8.6 (2008-03-03 patchlevel 114) [i686-darwin9.4.0]
  1 thread(s) x  10000000 = 3.510694
 10 thread(s) x   1000000 = 3.552756
 50 thread(s) x    200000 = 3.586885
100 thread(s) x    100000 = 3.574564&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Ruby 1.8.6 (installed with Leopard):&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;$ /usr/bin/ruby main.rb &amp;quot;`/usr/bin/ruby -v`&amp;quot; 10_000_000
ruby 1.8.6 (2008-03-03 patchlevel 114) [universal-darwin9.0]
   1 thread(s) x  10000000 = 6.586917
  10 thread(s) x   1000000 = 6.78801
  50 thread(s) x    200000 = 6.951003
 100 thread(s) x    100000 = 6.907087&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Ruby 1.8.7 (installed from MacPorts):&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;$ ruby main.rb   &amp;quot;`ruby -v`&amp;quot; 10_000_000
ruby 1.8.7 (2008-06-20 patchlevel 22) [i686-darwin9.4.0]
   1 thread(s) x  10000000 = 36.329174
  10 thread(s) x   1000000 = 36.808753
  50 thread(s) x    200000 = 36.715717
 100 thread(s) x    100000 = 36.499772   &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;To co niepokoi, to koszmarnie wolna praca Ruby 1.8.7 w por&#243;wnaniu do Ruby 1.8.6. To jest bardzo podejrzana sprawa. Cieszy za to dobra wydajno&#347;&#263; Ruby Enterprise.&lt;/p&gt;


	&lt;h3&gt;Python/Jython&lt;/h3&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;random&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="constant"&gt;Random&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;sys&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;argv&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;time&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="ident"&gt;time&lt;/span&gt;
&lt;span class="ident"&gt;from&lt;/span&gt; &lt;span class="ident"&gt;threading&lt;/span&gt; &lt;span class="ident"&gt;import&lt;/span&gt; &lt;span class="constant"&gt;Thread&lt;/span&gt;
&lt;span class="ident"&gt;rand&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Random&lt;/span&gt;&lt;span class="punct"&gt;().&lt;/span&gt;&lt;span class="ident"&gt;randint&lt;/span&gt; &lt;span class="comment"&gt;# alias&lt;/span&gt;

&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;ThreadTest(Thread):&lt;/span&gt;
   &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;__init__&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;iterations&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt; 
      &lt;span class="constant"&gt;Thread&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;__init__&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;              
      &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;iterations&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;iterations&lt;/span&gt;
   &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;run&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt; 
      &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;rand&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="constant"&gt;SIZE&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;for&lt;/span&gt; &lt;span class="ident"&gt;x&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="ident"&gt;xrange&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;iterations&lt;/span&gt;&lt;span class="punct"&gt;)]&lt;/span&gt;

&lt;span class="constant"&gt;SIZE&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;int&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;argv&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;2&lt;/span&gt;&lt;span class="punct"&gt;])&lt;/span&gt;
&lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="ident"&gt;argv&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;
&lt;span class="keyword"&gt;for&lt;/span&gt; &lt;span class="ident"&gt;nr&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;10&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;50&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;100&lt;/span&gt;&lt;span class="punct"&gt;]:&lt;/span&gt;
  &lt;span class="ident"&gt;iterations&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;SIZE&lt;/span&gt; &lt;span class="punct"&gt;/&lt;/span&gt; &lt;span class="ident"&gt;nr&lt;/span&gt;
  &lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt; %3d thread(s) x %9s = &lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;nr&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;iterations&lt;/span&gt;&lt;span class="punct"&gt;),&lt;/span&gt;
  &lt;span class="ident"&gt;start&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;time&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
  &lt;span class="ident"&gt;threads&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[]&lt;/span&gt;
  &lt;span class="keyword"&gt;for&lt;/span&gt; &lt;span class="ident"&gt;i&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="ident"&gt;range&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;nr&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;
     &lt;span class="ident"&gt;t&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;ThreadTest&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;iterations&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
     &lt;span class="ident"&gt;threads&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;append&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
     &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;start&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
  &lt;span class="keyword"&gt;for&lt;/span&gt; &lt;span class="ident"&gt;t&lt;/span&gt; &lt;span class="keyword"&gt;in&lt;/span&gt; &lt;span class="ident"&gt;threads&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;
     &lt;span class="ident"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;join&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
  &lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;%s s.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;%&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;time&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt; &lt;span class="punct"&gt;-&lt;/span&gt; &lt;span class="ident"&gt;start&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Test:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;$ python main.py &amp;quot;`python -V`&amp;quot; 10000000
Python 2.5.2
  1 thread(s) x  10000000 =  34.5188429356 s.
 10 thread(s) x   1000000 =  52.3496830463 s.
 50 thread(s) x    200000 =  53.9406650066 s.
100 thread(s) x    100000 =  58.3923280239 s.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Co ciekawe, Python 2.5.2 okaza&#322; si&#281; najwolniejszy. Im wi&#281;cej w&#261;tk&#243;w tym jeszcze wolniej dzia&#322;a&#322;. By&#322; wolniejszy nawet od (dziwnie wolnego) Ruby 1.8.6. Ale, by&#263; mo&#380;e to jest wina bardzo wolnej biblioteki generowania losowych liczb. Ech, jak tu cokolwiek por&#243;wnywa&#263; mi&#281;dzy j&#281;zykami jak takie odkrywa si&#281; takie babole w bibliotece standardowej Pythona.&lt;/p&gt;


	&lt;p&gt;Jython by&#322;&#160;jeszcze wolniejszy. Dla 10 mln. iteracji, mimo &#380;e nie by&#322;y tworzone w pami&#281;ci &#380;adne listy, wl&#243;k&#322; si&#281; tak wolno, &#380;e przerwa&#322;em test. Po zmniejszeniu iteracji o rz&#261;d wielko&#347;ci (do 1 miliona) uzyska&#322; wyniki takie jak Ruby 1.8.6 dla 10 milion&#243;w iteracji. Jython jest najwyra&#378;niej jeszcze bardzo s&#322;abo zoptymalizowany. Pomys&#322;y aby na nim odpala&#263; frameworki takie jak Django, to na razie raczej przedwczesny pomys&#322;.&lt;/p&gt;


	&lt;p&gt;Iterations: 1,000,000 instead of 10,000,000:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_bash "&gt;$ jython main.py &amp;quot;`jython --version`&amp;quot; 1000000
Jython 2.2.1 on java1.6.0_05

  10 thread(s) x    100000 =  6.391000032424927 s.
  50 thread(s) x     20000 =  4.368000030517578 s.
 100 thread(s) x     10000 =  4.352999925613403 s.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 26 Jul 2008 13:22:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:f3cdd08b-0fa8-4545-aa1a-8a2fcb4903ca</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/07/26/threads-ruby-python</link>
      <category>ruby</category>
      <category>python</category>
      <category>jruby</category>
      <category>jython</category>
      <category>java</category>
    </item>
    <item>
      <title>JRuby 1.1 final</title>
      <description>&lt;p&gt;Jest w ko&#324;cu oczekiwana wersja stabilna &lt;strong&gt;JRuby 1.1&lt;/strong&gt;. W chwili pisania tej notki, nie ma o tym jeszcze informacji &lt;a href="http://jruby.codehaus.org/"&gt;na stronie g&#322;&#243;wnej&lt;/a&gt;, ale jest ju&#380; &lt;a href="http://dist.codehaus.org/jruby/"&gt;do pobrania&lt;/a&gt;. To bardzo dobra wiadomo&#347;&#263;, bo JRuby 1.1 ju&#380; w wersjach rozwojowych by&#322; znacznie szybszy od poprzedniej 1.0, a w wielu testach bi&#322; wydajno&#347;ci&#261; nie tylko Ruby 1.8.6 i 1.9, ale tak&#380;e Pythona 2.5.1. Dzi&#281;ki JRuby webowe frameworki takie jak &lt;a href="http://rubyonrails.pl"&gt;Rails&lt;/a&gt; czy &lt;a href="http://merbivore.com/"&gt;Merb&lt;/a&gt; uzyskuj&#261; pe&#322;ny dost&#281;p do bibliotek Javy i tym samym jakiekolwiek uwagi co do (nie)dojrza&#322;o&#347;ci bibliotek Rubiego staj&#261; si&#281; nieistotne.&lt;/p&gt;</description>
      <pubDate>Mon, 31 Mar 2008 00:51:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:c7b2c8e8-bcd2-484d-b850-9b908c67015e</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/03/31/jruby11</link>
      <category>jruby</category>
      <category>ruby</category>
      <category>java</category>
    </item>
    <item>
      <title>Django on Jython</title>
      <description>&lt;p&gt;Pythonistas chyba pozazdro&#347;cili mo&#380;liwo&#347;ci odpalenia &lt;a href="http://rubyonrails.org"&gt;Rails&#243;w&lt;/a&gt; w &lt;a href="http://jruby.codehaus.org/"&gt;JRuby&lt;/a&gt;. Trwaj&#261; prace nad uruchomieniem frameworka &lt;a href="http://djangoproject.com"&gt;Django&lt;/a&gt; w &lt;a href="http://www.jython.org/Project/index.html"&gt;Jythonie&lt;/a&gt;, implementacji Pythona w czystej Javie.&lt;/p&gt;


	&lt;p&gt;Zapyta&#322;em si&#281; na kanale &lt;a href="irc://irc.eu.freenode.net/pylons"&gt;#pylons&lt;/a&gt; odno&#347;nie podobnego ruchu ze strony &lt;a href="http://pylonshq.com"&gt;Pylons&lt;/a&gt;, ale okazuje si&#281; &#380;e Jython jest dosy&#263; zacofany. Od czasu przej&#347;cia jego tw&#243;rcy do Microsoftu i pracy na &lt;a href="http://www.codeplex.com/Wiki/View.aspx?ProjectName=IronPython"&gt;IronPythonem&lt;/a&gt; projekt dosy&#263; powoli si&#281; rozwija. Jython zatrzyma&#322; si&#281; na implementacji Pythona 2.2. To dosy&#263; stara wersja zwa&#380;aj&#261;c, &#380;e w mi&#281;dzyczasie wysz&#322;y wersje 2.3, 2.4 i 2.5. Pylons wymaga zgodno&#347;ci min. z Pythonem 2.4. Nie wiem jak ten problem rozwi&#261;&#380;&#261; przy przenoszeniu Django, bo co&#347; nie chce mi si&#281; wierzy&#263; &#380;e jest w pe&#322;ni zgodny ze starym Pythonem 2.2.&lt;/p&gt;</description>
      <pubDate>Tue, 08 Jan 2008 04:34:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:4159d4c3-fcd0-442c-9d15-f96ae24099ea</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2008/01/08/django-on-jython</link>
      <category>django</category>
      <category>python</category>
      <category>jython</category>
      <category>java</category>
    </item>
    <item>
      <title>Jest w ko&#324;cu Java 6 dla Leoparda</title>
      <description>&lt;p&gt;Zar&#243;wno Apple jak i Sun si&#281; oci&#261;gaj&#261; z wypuszczeniem Javy 6 dla Leoparda (tj. Mac OS-X 10.5). W internecie mo&#380;na znale&#378;&#263; troch&#281; wkurzonych os&#243;b. Niekt&#243;rzy chc&#261; nawet s&#322;a&#263; petycje do Apple aby co&#347; z tym zrobili.&lt;/p&gt;


	&lt;p&gt;Na szcz&#281;&#347;cie, znalaz&#322; si&#281; jeden cz&#322;owiek (Landon Fuller) kt&#243;ry udost&#281;pni&#322; &lt;a href="http://landonf.bikemonkey.org/static/soylatte/"&gt;Jav&#281; 6 dla Leoparda&lt;/a&gt;. Gwoli &#347;cis&#322;o&#347;ci, przygotowa&#322; zar&#243;wno wersj&#281; 32 bitow&#261; dla Tigera i Leoparda jak i wersj&#281; 64-bitow&#261; (tylko dla Leoparda). Cho&#263; plik zawiera w nazwie s&#322;owo &amp;#8220;amd64&amp;#8221;, nie nale&#380;y si&#281; tym przejmowa&#263;. Dzia&#322;a bez problemu na MacIntelach.&lt;/p&gt;</description>
      <pubDate>Fri, 30 Nov 2007 12:34:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:caf0364b-22c9-4b1c-9960-680be6dfcbee</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2007/11/30/java6-leopard</link>
      <category>leopard</category>
      <category>osx</category>
      <category>java</category>
      <category>apple</category>
    </item>
    <item>
      <title>JRuby 1.0</title>
      <description>&lt;p&gt;Ukaza&#322;a si&#281; finalna wersja &lt;a href="http://jruby.codehaus.org/"&gt;JRuby 1.0&lt;/a&gt; &amp;#8211; implementacji j&#281;zyka &lt;a href="http://ruby-lang.org/"&gt;Ruby&lt;/a&gt; w czystej Javie. Zesp&#243;&#322; JRuby zach&#281;ca do testowania Rails&#243;w na JRuby. Z tego co pami&#281;tam, to wersji finalnej JRuby zapowiadano w&#322;&#261;czenie optymalizacji kodu. Zanim zatem wyjdzie w ko&#324;cu Ruby 2.0, JRuby on Rails ma ju&#380; teraz szans&#281; prze&#322;ama&#263; stereotyp o s&#322;abszej wydajno&#347;ci Rubiego. Szczeg&#243;lnie mo&#380;e to mie&#263; du&#380;e znaczenie dla platformy Windows, bo Ruby na systemach &lt;span class="caps"&gt;POSIX&lt;/span&gt; (Linux, &lt;span class="caps"&gt;BSD&lt;/span&gt;, Mac &lt;span class="caps"&gt;OS X&lt;/span&gt;) pracuje znacznie wydajniej.&lt;/p&gt;


	&lt;p&gt;Dla mi&#322;o&#347;nik&#243;w Mac &lt;span class="caps"&gt;OS X&lt;/span&gt; jest dost&#281;pny &lt;a href="http://www.techcfl.com/blog/?p=109"&gt;artyku&#322; pokazuj&#261;cy jak skonfigurowa&#263;&lt;/a&gt; ca&#322;e &#347;rodowisko Javy dla Rail. Ale do pracy z Rails, najpro&#347;ciej u&#380;y&#263; &lt;a href="http://deadlock.nbextras.org/hudson/job/ruby/"&gt;Netbeans 6&lt;/a&gt; kt&#243;ry od jakiego&#347; czasu pozwala&lt;sup&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt; na uruchamianie Rails&#243;w na JRuby (mo&#380;na wybra&#263; sobie opcj&#281; JRuby lub klasyczny CRuby).&lt;/p&gt;


	&lt;p&gt;Zobacz te&#380; artyku&#322; &amp;#8220;&lt;a href="http://java.sun.com/developer/technicalArticles/scripting/jruby/"&gt;JRuby and the Java Platform&lt;/a&gt;&amp;#8221; jaki ukaza&#322; si&#281; wczoraj na stronie firmy Sun.&lt;/p&gt;


&lt;hr size="1" width="30%" align="left" /&gt;

	&lt;p id="fn1"&gt;&lt;sup&gt;1&lt;/sup&gt; Szkoda, &#380;e &lt;span class="caps"&gt;NB6&lt;/span&gt; nie ma jeszcze zaimplementowanego kolorowania i podpowiadania helper&#243;w dla &lt;a href="http://haml.hamptoncatlin.com/"&gt;Haml&lt;/a&gt;. Jak kto&#347; ma si&#322;y i czas to tu jest opis jak &lt;a href="http://platform.netbeans.org/tutorials/nbm-mfsyntax.html"&gt;doda&#263; kolorowanie&lt;/a&gt; dla jakiego&#347; innego j&#281;zyka.&lt;/p&gt;</description>
      <pubDate>Wed, 13 Jun 2007 11:24:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:597062a5-308f-4772-8199-d0b695a2b515</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2007/06/13/jruby-1-0</link>
      <category>jruby</category>
      <category>java</category>
      <category>ruby</category>
      <category>rails</category>
    </item>
    <item>
      <title>Jython 2.2beta1</title>
      <description>&lt;p&gt;Pog&#322;oski o przedwczesnej &#347;mierci Jythona (javowej implementacji &lt;a href="http://python.org"&gt;Pythona&lt;/a&gt;),  s&#261; chyba przesadzone. W&#322;a&#347;nie wysz&#322;a kolejna wersja &lt;a href="http://www.jython.org/Project/index.html"&gt;2.2 beta1&lt;/a&gt;. Instalacja:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;java&lt;/span&gt; &lt;span class="punct"&gt;-&lt;/span&gt;&lt;span class="ident"&gt;jar&lt;/span&gt; &lt;span class="ident"&gt;jython_installer&lt;/span&gt;&lt;span class="punct"&gt;-&lt;/span&gt;&lt;span class="number"&gt;2.2&lt;/span&gt;&lt;span class="ident"&gt;b1&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;jar&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <pubDate>Fri, 09 Feb 2007 22:51:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:aac669f6-93d2-4f57-93d6-df464b92030d</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2007/02/09/jython-2-2beta1</link>
      <category>jython</category>
      <category>java</category>
      <category>python</category>
    </item>
    <item>
      <title>Serwery kontynuacyjne - przysz&#322;o&#347;&#263; webu</title>
      <description>&lt;p&gt;Ka&#380;dy, kto zajmowa&#322; si&#281; kiedykolwiek programowaniem stron internetowych wie, &#380;e protok&#243;&#322; &lt;span class="caps"&gt;HTTP&lt;/span&gt; jest bezstanowy. Innymi s&#322;owy, ka&#380;de prze&#322;adowanie strony  internetowej generuje kompletnie niezale&#380;ne wywo&#322;anie serwera i nie ma on mo&#380;liwo&#347;ci aby powi&#261;za&#263; wywo&#322;anie z konkretnym klientem. Aby temu zaradzi&#263;, wprowadzono prost&#261; sztuczk&#281;. Wprowadzono tzw. mechanizm cookies (dos&#322;. ciasteczek), malutkich plik&#243;w kt&#243;re serwer mo&#380;e wysy&#322;a&#263; do klienta (tam i z powrotem). Ten unikalny identyfikator (sesji)  mo&#380;na te&#380; trzyma&#263; w adresie &lt;span class="caps"&gt;URL&lt;/span&gt;, ale ta metoda jest zdecydowanie odradzana z powodu &#322;atwo&#347;ci nadu&#380;y&#263; (&#322;atwo wykra&#347;&#263; taki numer i podszy&#263; si&#281; pod autora) Od strony klienta jedynym wymaganiem jest aby nie blokowa&#322; sobie w przegl&#261;darce mechanizmu cookies.&lt;/p&gt;


	&lt;p&gt;Serwer znaj&#261;c identyfikator sesji, mo&#380;e zwi&#261;za&#263; z nim szereg danych, np. aktualn&#261; list&#281; zamawianych produkt&#243;w w&#322;o&#380;onych do koszyka w sklepie internetowym. Dane te zwykle trzyma si&#281; w bazie lub w pami&#281;ci operacyjnej. Oczywi&#347;cie czas &#380;ycia danych jest ustalany przez serwet i w normalnym wypadku s&#261; one cyklicznie kasowane. (Z tym &amp;#8220;normalnym&amp;#8221; wypadkiem to r&#243;&#380;nie bywa, bo wiele framework&#243;w tego nie zapewnia i trzeba samemu o to zadba&#263;)&lt;/p&gt;


	&lt;p&gt;Mechanizm sesji jest dosy&#263; wydajny, bo zapytania wysy&#322;ane do serwera mog&#261; by&#263; obs&#322;ugiwane &lt;strong&gt;asynchronicznie&lt;/strong&gt;, czyli bez &#380;adnych blokad w oczekiwaniu na uko&#324;czenie obs&#322;ugi zapytania. Przez lata &amp;#8220;stanowo&#347;&#263;&amp;#8221; protoko&#322;u &lt;span class="caps"&gt;HTTP&lt;/span&gt; zapewnia&#322;o si&#281; w&#322;a&#347;nie za pomoc&#261; sesji.&lt;/p&gt;


	&lt;p&gt;Ten mechanizm ma jednak swoje wady. Najwi&#281;ksz&#261; jest &lt;strong&gt;z&#322;o&#380;ono&#347;&#263;&lt;/strong&gt; jak&#261; wprowadza po stronie skrypt&#243;w na serwerze. (I to nie jest wcale taka trywialna sprawa jak to mo&#380;na by&#322;o zaobserwowa&#263; u developer&#243;w frameworka CherryPy kt&#243;rzy miesi&#261;cami nie potrafili napisa&#263; stabilnie dzia&#322;aj&#261;cego mechanizmu obs&#322;ugi sesji.)&lt;/p&gt;


	&lt;h3&gt;Kontynuacje&lt;/h3&gt;


	&lt;p&gt;Kompletnie innym podej&#347;ciem jest skorzystanie z tzw. mechanizmu kontynuacji.  Mechanizm ten podobny jest do gracza, kt&#243;ry w dowolnym momencie mo&#380;e zapisa&#263; i wczyta&#263; stan gry.  Kontynuacje zapewniaj&#261; taki mechanizm zapisu stanu programu aby w dowolnym momencie p&#243;&#378;niej go przywr&#243;ci&#263;. Niekt&#243;rzy por&#243;wnuj&#261; to do maszyny czasu, bo mo&#380;na w dowolnym momencie przywr&#243;ci&#263; wcze&#347;niejszy stan aplikacji.&lt;/p&gt;


	&lt;p&gt;Zalet z takiego podej&#347;cia jest wiele. We&#378;my np. spraw&#281; obs&#322;ugi &amp;#8220;nie&#347;miertelnego&amp;#8221; przycisku Back w przegl&#261;darce. Obs&#322;uga tego przycisku sprawia spore problemy. Programi&#347;ci najch&#281;tniej w og&#243;le by go zablokowali. W wypadku kontynuacji ten problem w og&#243;le nie istnieje. Klikn&#261;&#322; kto&#347; Back aby cofn&#261;&#263; si&#281; do poprzedniej strony? &#379;aden problem. Serwer przywr&#243;ci ca&#322;y wcze&#347;niejszy stan aplikacji bez &#380;adnego problemu. I to w spos&#243;b &lt;strong&gt;przezroczysty&lt;/strong&gt; dla programisty! Programowanie stron webowych staje si&#281; &lt;strong&gt;znacznie prostsze&lt;/strong&gt;, niczym tworzenie aplikacji desktopowej w&#322;&#261;cznie z debugowaniem krok po kroku. Wg r&#243;&#380;nych prognoz, tak b&#281;dziemy programowa&#263; serwisy internetowe za kilka lat!&lt;/p&gt;


	&lt;p&gt;Sama idea nie jest najwyra&#378;niej jeszcze powszechnie znana, skoro w rozmowie z developerami irlandzkiego Google, zaskoczy&#322;em ich informacj&#261; na ten temat. Kto wie, czy Google mocniej nie zainwestuje w Rubiego (aktualnie mocno korzysta z Pythona, kt&#243;ry jest podstaw&#261; wi&#281;kszo&#347;ci ich skrypt&#243;w).&lt;/p&gt;


	&lt;h3&gt;Smalltalk i Seaside&lt;/h3&gt;


	&lt;p&gt;Smalltalk jest bardzo starym j&#281;zykiem bo jego pocz&#261;tki si&#281;gaj&#261; lat 70-tych. Od zawsze by&#322; j&#281;zykiem w pe&#322;ni obiektowym i dynamicznym. To m.in. Smalltalk pierwszy wymy&#347;li&#322; wirtualn&#261; maszyn&#281; kt&#243;rej to ide&#281; p&#243;&#378;niej skopiowali tw&#243;rcy Javy. W Smalltalku napisano najlepszy (w chwili obecnej) na &#347;wiecie &lt;strong&gt;serwer kontynuacyjny &amp;#8211; &lt;a href="http://www.seaside.st/"&gt;Seaside&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;


	&lt;p&gt;Czy to spowoduje renesans na Smalltalka? Osobi&#347;cie w to w&#261;tpi&#281;. G&#322;&#243;wn&#261; wad&#261; Smalltalka jest jego monolityczno&#347;&#263; i hermentyczno&#347;&#263;. Uruchamiaj&#261;c &#347;rodowisko Smalltalak uruchamia si&#281; ca&#322;y, zamkni&#281;ty &#347;wiat Smalltalka. Np. nie ma tam dost&#281;pu do plik&#243;w z zewn&#261;trz tak, jak w innych j&#281;zykach. To spowodowa&#322;o, &#380;e j&#281;zyk ten, mimo pewnych sukces&#243;w, nigdy nie zdoby&#322; sobie powszechnego uznania. I moim zdanie, nigdy ju&#380; nie zdob&#281;dzie, bo w mi&#281;dzyczasie wyros&#322;a mu m&#322;oda, obiecuj&#261;ca konkurencja.&lt;/p&gt;


	&lt;h3&gt;Ruby&lt;/h3&gt;


	&lt;p&gt;Ruby jest j&#281;zykiem relatywnie m&#322;odym. Tzn. zosta&#322; po raz pierwszy udost&#281;pniony publicznie w tym samym roku co Java &amp;#8211; 1995. Ale przez wi&#281;kszo&#347;&#263; lat by&#322; ma&#322;o znany poza Japoni&#261; (sk&#261;d pochodzi jego tw&#243;rca).  Ruby jest tak&#380;e  jednym z tych nielicznych j&#281;zyk&#243;w, kt&#243;re (podobnie jak Smalltalk) posiadaj&#261; wbudowan&#261; obs&#322;ug&#281; kontynuacji. Istniej&#261; co prawda r&#243;&#380;ne pr&#243;by implementacji tego mechanizmu w Javie&lt;sup&gt;&lt;a href="#fn1"&gt;1&lt;/a&gt;&lt;/sup&gt;, ale tylko Ruby posiada ten mechanizm jako co&#347; naturalnego i nie trzeba stosowa&#263; &#380;adnych specjalnych sztuczek aby go emulowa&#263;. Z tego co pami&#281;tam, Seaside pierwotnie by&#322; tworzony w Ruby, ale w tamtym okresie, kontynuacje w Ruby by&#322;y jeszcze niedojrza&#322;e, wi&#281;c tw&#243;rcy przerzucili si&#281; na Smalltalka. Ruby jednak szybko si&#281; rozwija, nabiera dojrza&#322;o&#347;ci i moim zdaniem, ma bardzo du&#380;e szanse, aby wyprzedzi&#263; pozosta&#322;e j&#281;zyki przy tworzeniu serwis&#243;w internetowych nowej generacji, serwis&#243;w opartych na kontynuacjach.&lt;/p&gt;


	&lt;h3&gt;Przyk&#322;ad kontynuacji.&lt;/h3&gt;


	&lt;p&gt;Poni&#380;szy przyk&#322;ad&lt;sup&gt;&lt;a href="#fn2"&gt;2&lt;/a&gt;&lt;/sup&gt; pokazuje implementacj&#281; generatora za pomoc&#261; kontynuacji.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Generator&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;
    &lt;span class="ident"&gt;do_generation&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;next&lt;/span&gt;
    &lt;span class="ident"&gt;callcc&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;here&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
      &lt;span class="attribute"&gt;@main_context&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;here&lt;/span&gt;&lt;span class="punct"&gt;;&lt;/span&gt;
       &lt;span class="attribute"&gt;@generator_context&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;call&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;

   &lt;span class="ident"&gt;private&lt;/span&gt;

   &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;do_generation&lt;/span&gt;
     &lt;span class="ident"&gt;callcc&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;context&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
       &lt;span class="attribute"&gt;@generator_context&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;context&lt;/span&gt;&lt;span class="punct"&gt;;&lt;/span&gt;
       &lt;span class="keyword"&gt;return&lt;/span&gt;
     &lt;span class="keyword"&gt;end&lt;/span&gt;
     &lt;span class="ident"&gt;generating_loop&lt;/span&gt;
   &lt;span class="keyword"&gt;end&lt;/span&gt;

   &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;generate&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;value&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
     &lt;span class="ident"&gt;callcc&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;context&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;
       &lt;span class="attribute"&gt;@generator_context&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;context&lt;/span&gt;&lt;span class="punct"&gt;;&lt;/span&gt;
       &lt;span class="attribute"&gt;@main_context&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;call&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;value&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
     &lt;span class="keyword"&gt;end&lt;/span&gt;
   &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;A oto oparty na nim generator ci&#261;gu liczb Fibbonacciego:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;FibGenerator&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&lt;/span&gt; &lt;span class="constant"&gt;Generator&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;generating_loop&lt;/span&gt;
    &lt;span class="ident"&gt;generate&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="ident"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;b&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;
    &lt;span class="ident"&gt;loop&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;
      &lt;span class="ident"&gt;generate&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;b&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
      &lt;span class="ident"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;b&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;b&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;+&lt;/span&gt;&lt;span class="ident"&gt;b&lt;/span&gt;
    &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="ident"&gt;fib&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;FibGenerator&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
&lt;span class="number"&gt;15&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;times&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{fib.next}&lt;/span&gt; &lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;
&lt;span class="comment"&gt;#wynik: 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 &lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p id="fn1"&gt;&lt;sup&gt;1&lt;/sup&gt; Np. &lt;a href="http://rifers.org/"&gt;Riff&lt;/a&gt; lub &lt;a href="http://jetty.mortbay.org/jetty/"&gt;Jetty 6&lt;/a&gt;.&lt;/p&gt;


	&lt;p id="fn2"&gt;&lt;sup&gt;2&lt;/sup&gt; Przyk&#322;ad z ksi&#261;&#380;ki &amp;#8220;The Ruby Way&amp;#8221;, 1ed.&lt;/p&gt;</description>
      <pubDate>Wed, 22 Nov 2006 02:26:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:c15ba4a7-3852-452b-af70-9f5ea30a4702</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2006/11/22/serwery-kontynuacyjne-przysz%C5%82o%C5%9B%C4%87-webu</link>
      <category>Ruby</category>
      <category>Java</category>
      <category>SmallTalk</category>
      <category>ruby</category>
      <category>smalltalk</category>
      <category>java</category>
      <category>continuations</category>
    </item>
    <item>
      <title>Sun zatrudni&#322; programist&#243;w JRuby</title>
      <description>&lt;p&gt;W &#347;rodowisku javowc&#243;w &lt;a href="http://ruby-lang.org/"&gt;Ruby&lt;/a&gt; jest j&#281;zykiem kt&#243;ry robi troch&#281; zamieszania (jako&#347; tak si&#281; sk&#322;ada, &#380;e Ruby bardziej przemawia do programist&#243;w Javy ni&#380; &lt;a href="http://python.org"&gt;Python&lt;/a&gt;).  Cieszy zatem, &#380;e firma Sun podj&#281;&#322;a decyzj&#281; o wsparciu projektu &lt;a href="http://jruby.codehaus.org/"&gt;JRuby&lt;/a&gt; &lt;a href="http://www.tbray.org/ongoing/When/200x/2006/09/07/JRuby-guys"&gt;zatrudniaj&#261;c&lt;/a&gt; jego czo&#322;owych developer&#243;w.  Powinno to znacznie przy&#347;pieszy&#263; prace nad tym projektem podobnie jak sta&#322;o si&#281; z &lt;a href="http://www.codeplex.com/Wiki/View.aspx?ProjectName=IronPython"&gt;IronPythonem&lt;/a&gt;, gdy Microsoft zatrudni&#322; jego tw&#243;rc&#281;.&lt;/p&gt;


	&lt;p&gt;Jestem ciekaw jak d&#322;ugo programi&#347;ci zachowaj&#261; entuzjazm dla swego j&#281;zyka, gdy b&#281;dzie mo&#380;na generowa&#263; taki sam bytecode Javy lecz w niezr&#243;wnanie prostszy spos&#243;b. :)&lt;/p&gt;


	&lt;p&gt;Przyk&#322;adowy kod Javy:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_java "&gt;public class Filter {
  public static void main(String[] args) {
    List list = new java.util.ArrayList();
    list.add(&amp;quot;Tim&amp;quot;); list.add(&amp;quot;Ike&amp;quot;); list.add(&amp;quot;Tina&amp;quot;);
    Filter filter = new Filter();
    for (String item : filter.filterLongerThan(list, 3)) { 
      System.out.println( item ); 
    }
  }
  public List filterLongerThan(List list, int length) {
    List result = new ArrayList();
    for (String item : list) {
      if (item.length() &amp;lt;= length) { result.add( item ); }
    }
    return result;
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;A oto odpowiadaj&#261;cy mu kod  w Ruby:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="ident"&gt;list&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;['&lt;/span&gt;&lt;span class="string"&gt;Tim&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Ike&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;Tina&lt;/span&gt;&lt;span class="punct"&gt;']&lt;/span&gt;
&lt;span class="ident"&gt;list&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;select&lt;/span&gt; &lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;n&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;n&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;length&lt;/span&gt; &lt;span class="punct"&gt;&amp;gt;&lt;/span&gt; &lt;span class="number"&gt;3&lt;/span&gt;&lt;span class="punct"&gt;}.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="punct"&gt;{|&lt;/span&gt;&lt;span class="ident"&gt;n&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;n&lt;/span&gt;&lt;span class="punct"&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Oczywi&#347;cie to nie wszystko. Dzi&#281;ki JRuby mo&#380;na uzyska&#263; efekty kompletnie nieosi&#261;galne w standardowej Javie &amp;#8211; np. mo&#380;na pracowa&#263; z bibliotek&#261; Swing w spos&#243;b &lt;strong&gt;interaktywny&lt;/strong&gt;, z poziomu interpretera zmieniaj&#261;c na &#380;ywo jej obiekty.&lt;/p&gt;


	&lt;p&gt;Wkr&#243;tce ma tak&#380;e by&#263; gotowa &lt;strong&gt;wersja Rails&#243;w dzia&#322;aj&#261;ca z  JRuby&lt;/strong&gt; (Zobacz prezentacj&#281; w &lt;a href="http://dist.codehaus.org/jruby/jruby_presentation_may06.ppt"&gt;PowerPoint&lt;/a&gt;).  Tym samym odesz&#322;yby wszelkie uwagi co do wydajno&#347;ci Rails&#243;w, bo wsp&#243;&#322;czesna wirtualna maszyna Javy jest tak silnie zoptymalizowna &#380;e dor&#243;wnuje j&#281;zykowi C++. Oczywi&#347;cie model w&#261;tkowy JRuby jest zgodny z wydajnym i dojrza&#322;ym modelem w&#261;tkowym Javy &amp;#8211; po prostu z niego korzysta.&lt;/p&gt;</description>
      <pubDate>Fri, 08 Sep 2006 10:33:00 +0200</pubDate>
      <guid isPermaLink="false">urn:uuid:d35f513c-939f-4f71-9392-e4d9f95c11ee</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2006/09/08/sun-zatrudni%C5%82-programist%C3%B3w-jruby</link>
      <category>Ruby</category>
      <category>Java</category>
      <category>ruby</category>
      <category>java</category>
      <category>jruby</category>
    </item>
    <item>
      <title>Akcesory w Javie, Pythonie, Ruby i PHP5</title>
      <description>&lt;p&gt;Java, j&#281;zyk kt&#243;ry doby&#322; sobie siln&#261; pozycj&#281; na rynku korporacyjnym, jest od jakiego&#347; czasu pod obstrza&#322;em krytyki z r&#243;&#380;nych stron. Wysz&#322;a ca&#322;a seria ksi&#261;&#380;ek krytykuj&#261;cych model obiektowy oraz  metodologie promowane przez Jav&#281; (od najs&#322;ynniejszej &lt;a href="http://www.amazon.com/gp/product/0596100949/"&gt;&lt;strong&gt;Beyond Java&lt;/strong&gt;&lt;/a&gt; po &lt;a href="http://www.manning.com/books/tate"&gt;Bitter Java&lt;/a&gt;, &lt;a href="http://www.manning.com/books/tate2"&gt;Bitter &lt;span class="caps"&gt;EJB&lt;/span&gt;&lt;/a&gt;, czy inne)&lt;/p&gt;


	&lt;p&gt;Nie umniejszaj&#261;c zalet Javy, jej krytycy wytykaj&#261; jej niepotrzebn&#261; nadmiarowo&#347;&#263; kodu, oci&#281;&#380;a&#322;o&#347;&#263; i ma&#322;&#261; zwrotno&#347;&#263;, kt&#243;ra powoduje &#380;e j&#281;zyk ten s&#322;abo nadaje si&#281; do modnej ostatnio metodologii _&lt;a href="http://agilemanifesto.org/"&gt;agile programming&lt;/a&gt;. _ Aby lepiej ten problem zobaczy&#263;, przyjrzyjmy si&#281; typowej praktyce programist&#243;w Javy. Tekst ten zainspirowany jest &lt;a href="http://jdn.pl/node/520"&gt;niedawn&#261; dyskusj&#261;&lt;/a&gt; jaka mia&#322;a miejsce w jednym z blog&#243;w mojego kolegi.&lt;/p&gt;


	&lt;h3&gt;Czym s&#261; akcesory?&lt;/h3&gt;


	&lt;p&gt;Akcesory (lub inaczej: gettery i settery) to slangowe okreslenie metod jakie u&#380;ywa obiekt do odczytu i modyfikacji swoich atrybut&#243;w. S&#261; one tak nagminnie u&#380;ywane przez programist&#243;w Javy, &#380;e niekt&#243;re edytory (np. Eclipse) zosta&#322;y nawet wyposa&#380;one w makra do automatycznego ich generowania.&lt;/p&gt;


	&lt;h3&gt;Dorzucanie nieu&#380;ywanego kodu &amp;#8220;na wszelki wypadek&amp;#8221;...&lt;/h3&gt;


	&lt;p&gt;Nagminna (w&#347;r&#243;d programist&#243;w Javy) praktyka dodawania akcesor&#243;w do atrybut&#243;w klasy pachnie jakim&#347; &lt;a href="http://en.wikipedia.org/wiki/Antipattern"&gt;antipatternem&lt;/a&gt;  i s&#261; g&#322;osy, kt&#243;re u&#380;ywanie akcesor&#243;w nazwyaj&#261; wprost &lt;a href="http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html"&gt;z&#322;&#261; praktyk&#261;&lt;/a&gt; . Jest w tym troch&#281; racji. Ale, jak to poni&#380;ej wyka&#380;&#281;, jest to pewnego rodzaju kompromis w zwi&#261;zku ze s&#322;abym modelem obiektowy Javy.&lt;/p&gt;


	&lt;p&gt;Dlaczego programi&#347;ci Javy generuj&#261; akcesory dla ka&#380;dego atrybutu nawet, jak nie przewiduj&#261; potrzeby ich u&#380;ywania? Ot&#243;&#380; czyni&#261; to &amp;#8220;na wszelki wypadek&amp;#8221; bo nie wiedz&#261;, czy w przysz&#322;o&#347;ci nie b&#281;dzie im to potrzebne&amp;#8230;&lt;/p&gt;


	&lt;p&gt;We&#378;my np. taki kod (z powodu kolejnego ograniczenia Javy nie mo&#380;na w jednym pliku trzyma&#263; wi&#281;cej, ni&#380; jednej klasy; tu dla kr&#243;tko&#347;ci umieszczam kod z obu plik&#243;w razem)&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_java "&gt;public class First {
  public String msg = &amp;quot;hello&amp;quot;;
}

public class Second extends First {
  public static void main(String[] args) {
    First obj = new First();        
    System.out.println(obj.msg);
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Jak wida&#263;, w Javie mo&#380;na si&#281;ga&#263; do atrybutu w spos&#243;b bezpo&#347;redni.&lt;/p&gt;


	&lt;p&gt;Wyobra&#378;my sobie jednak, &#380;e projekt nam si&#281; rozr&#243;s&#322; i mamy ju&#380; ca&#322;kiem sporo kodu oraz sporo plik&#243;w (pomna&#380;anych wydatnie przez javowe ograniczenia co do ilo&#347;ci klas mog&#261;cych wyst&#261;pi&#263; w pliku). Teraz przychodzi polecenie aby w momencie odczytu i zapisu atrybutu co&#347; dodatkowego wykona&#263;. (Np. niech to b&#281;dzie logowanie informacji o takim zdarzeniu, albo zablokowanie mo&#380;liwo&#347;ci modyfikacji tre&#347;ci atrybutu. Wszystko jedno co)&lt;/p&gt;


	&lt;p&gt;Mamy zatem pierwszy problem. Trzeba w tych wszystkich milionach miejsc, gdzie odwo&#322;ywali&#347;my si&#281; bezpo&#347;rednio do atrybut&#243;w, wymieni&#263; kod&amp;#8230;&lt;/p&gt;


	&lt;p&gt;W&#322;a&#347;nie dlatego, aby takich niespodzianek unikn&#261;&#263; w przysz&#322;o&#347;ci, programi&#347;ci Javy dorzucaj&#261; dodatkowe metody opakowuj&#261;ce odczyt i zapis atrybut&#243;w. Eclipse upraszcza ten proces zwalniaj&#261;c programist&#281; od r&#281;cznego wpisywania tego kodu.&lt;/p&gt;


	&lt;p&gt;Klasa First po zmianie:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_java "&gt;public class First {
  public String msg = &amp;quot;hello&amp;quot;;
  public String getMsg() {
    return msg;
  }
  public void setMsg(String msg) {
    this.msg = msg;
  }
}&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Wydaje si&#281;, &#380;e problem jest rozwi&#261;zany. Ale to dopiero pocz&#261;tek innych problem&#243;w.&lt;/p&gt;


	&lt;p&gt;Je&#347;li  bowiem, automatycznie dorzucamy te metody do wszystkich tysi&#281;cy atrybut&#243;w nowo tworzonych klas, to pierwsz&#261; rzecz&#261; kt&#243;r&#261; zauwa&#380;amy, jest nag&#322;e &amp;#8220;spuchni&#281;cie kodu&amp;#8221;. &lt;em&gt;Mamy kup&#281; nieu&#380;ywanych linii kodu, z kt&#243;rych prawdopodobnie wi&#281;kszo&#347;&#263; nie b&#281;dzie nigdy u&#380;ywana!&lt;/em&gt;&lt;/p&gt;


	&lt;p&gt;Ale to nie wszystko. Za&#322;&#243;&#380;my, &#380;e stajemy przed potrzeb&#261; &lt;em&gt;zmiany nazwy atrybutu&lt;/em&gt;. Oczywi&#347;cie, mo&#380;emy to zmieni&#263; w jednym miejscu (w ciele akcesora), ale wtedy wprowadzamy chaos w pozosta&#322;ej cz&#281;&#347;ci odno&#347;nie&amp;#8230; nazw (atrybut &amp;#8220;msg&amp;#8221; zmieniony na &amp;#8220;title&amp;#8221; troch&#281; g&#322;upio wygl&#261;da z akcesorami o nazwie &amp;#8220;getMsg&amp;#8221; i &amp;#8220;setMsg&amp;#8221;) Musimy przekopa&#263; si&#281; przez miliony miejsc w kodzie i pozmienia&#263; nazwy starym wywo&#322;aniom.&lt;/p&gt;


	&lt;p&gt;Zobaczmy jak ta sytuacja wygl&#261;da w j&#281;zykach dynamicznych.&lt;/p&gt;


	&lt;h3&gt;Python&lt;/h3&gt;


	&lt;p&gt;Python (podobnie jak Java) pozwala na bezpo&#347;redni dost&#281;p do atrybut&#243;w klasy. A co w sytuacji kiedy chcemy opakowa&#263; atrybut akcesorami? Nic prostszego. &lt;em&gt;Python pozwala na dodanie akcesor&#243;w wtedy, i tylko wtedy, kiedy s&#261; potrzebne. Na dodatek czyni to w spos&#243;b ca&#322;kowicie przezroczysty dla pozosta&#322;ej cz&#281;&#347;ci kodu.&lt;/em&gt; Programista Javy mo&#380;e sobie o tym tylko pomarzy&#263;.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;X(object):&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;get_msg&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;
    &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;__msg&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;set_msg&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;val&lt;/span&gt;&lt;span class="punct"&gt;):&lt;/span&gt;
    &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;__msg&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;val&lt;/span&gt;
  &lt;span class="ident"&gt;msg&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;property&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;get_msg&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;set_msg&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;

&lt;span class="ident"&gt;obj&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;X&lt;/span&gt;&lt;span class="punct"&gt;()&lt;/span&gt;
&lt;span class="ident"&gt;obj&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;msg&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;hello&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="ident"&gt;print&lt;/span&gt; &lt;span class="ident"&gt;obj&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;msg&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Python pozwala tak&#380;e zwi&#261;za&#263; z dowoln&#261; metod&#261;, atrybutem, klas&#261; czy modu&#322;em &lt;em&gt;docstring&lt;/em&gt;, czyli tekst z dokumentacj&#261;, obja&#347;nieniem itp. To jedna z genialnych cech Pythona specjalnie pomy&#347;lana dla leniwych programist&#243;w, kt&#243;rym nie chce si&#281; pisa&#263; dokumentacji. ;)&lt;/p&gt;


	&lt;h3&gt;Ruby&lt;/h3&gt;


	&lt;p&gt;W j&#281;zyku Ruby z definicji nie ma &#380;adnej mo&#380;liwo&#347;ci dost&#281;pu do atrubut&#243;w klasy inaczej jak przez akcesory. Odpada wi&#281;c problem zapominania aby je doda&#263;. Ruby jednak narzuca nazwy dla akcesor&#243;w (maj&#261; nazw&#281; tak&#261; jak atrybut!) i ca&#322;o&#347;&#263; wygl&#261;da tak, jakby operowano bezpo&#347;rednio na atrybucie.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;X&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;msg&lt;/span&gt;
    &lt;span class="attribute"&gt;@msg&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;msg=&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;val&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;
    &lt;span class="attribute"&gt;@msg&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;val&lt;/span&gt;
  &lt;span class="keyword"&gt;end&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;

&lt;span class="ident"&gt;obj&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;X&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;
&lt;span class="ident"&gt;obj&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;msg&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;hello&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;
&lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="ident"&gt;obj&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;msg&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

Dla os&#243;b, kt&#243;re nie lubi&#261; za du&#380;o pisa&#263;, Ruby ma wygodne skr&#243;ty. Powy&#380;sz&#261; definicj&#281; klasy mo&#380;na zapisa&#263; tak&#380;e w ten spos&#243;b:
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_ruby "&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;X&lt;/span&gt;
  &lt;span class="ident"&gt;attr_accessor&lt;/span&gt; &lt;span class="symbol"&gt;:msg&lt;/span&gt;
&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Istniej&#261; tak&#380;e oddzielne skr&#243;ty dla getter&#243;w i setter&#243;w. No i mo&#380;na po przecinku doda&#263; akcesory dla ca&#322;ej grupy atrybut&#243;w.&lt;/p&gt;


	&lt;h3&gt;&lt;span class="caps"&gt;PHP5&lt;/span&gt;&lt;/h3&gt;


	&lt;p&gt;&lt;span class="caps"&gt;PHP&lt;/span&gt; w wersji 5 ma przebudowany model obiektowy od podstaw. Tw&#243;rcy j&#281;zyka &lt;span class="caps"&gt;PHP&lt;/span&gt; nie starali si&#281; poprawia&#263; modelu obiektowego &lt;span class="caps"&gt;PHP4&lt;/span&gt; (by&#322; on tak z&#322;y, &#380;e pro&#347;ciej by&#322;o im napisa&#263; go od nowa). W nowym &lt;span class="caps"&gt;PHP5&lt;/span&gt; mamy ju&#380; mo&#380;liwo&#347;&#263; przezroczystego dodania akcesora.&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_php "&gt;&amp;lt;?php
class X {
  private $attributes = array('msg'=&amp;gt;null);
  private function __get($attrname) {
    return $this-&amp;gt;attributes[$attrname];
  }
  private function __set($attrname, $val) {
    $this-&amp;gt;attributes[$attrname] = $val;
  }
}

$obj = new X();
$obj-&amp;gt;msg = &amp;quot;hello&amp;quot;;
print $obj-&amp;gt;msg;
?&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Sk&#322;adnia mo&#380;e nie jest tak prosta jak w Ruby, ale (przynajmniej w tym miejscu), &lt;span class="caps"&gt;PHP5&lt;/span&gt; zachowuje si&#281; tu sensownie i unika dylemat&#243;w Javy.&lt;/p&gt;</description>
      <pubDate>Tue, 07 Feb 2006 23:25:00 +0100</pubDate>
      <guid isPermaLink="false">urn:uuid:3c61a0f6-2070-4178-b4fb-4db526cb572e</guid>
      <author>Jaros&#322;aw Zabie&#322;&#322;o</author>
      <link>http://blog.zabiello.com/articles/2006/02/07/akcesory-w-javie-pythonie-ruby-i-php5</link>
      <category>Python</category>
      <category>Ruby</category>
      <category>Java</category>
      <category>java</category>
      <category>php</category>
      <category>python</category>
      <category>ruby</category>
    </item>
  </channel>
</rss>
