Hatena::ブログ(Diary)

矢野勉のはてな日記 このページをアンテナに追加 RSSフィード Twitter

2006 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 08 | 09 | 10 | 11 | 12 |
2012 | 01 | 02 |

2006-12-16

そろそろRuby/PythonのようなLLを褒めるのにJavaを貶めるのは止めません?


もうURLを失念するくらいいろんなところで言われていることですけど、LL(Lightweight LanguageRubyPython,Perlのような軽量なスクリプト言語)との比較で出てくるJavaコードは、「普通こんなコードかかないでしょ」というくらい冗長な場合が多い。


Rubyでコードが簡潔に書ける!ということを表す時にJavaを引き合いに出すのはいいんですけど(引き合いに出す相手としては間違ってないと思います)、Javaのこんな長いコードがRubyではこんなに簡潔に!とか言う時のJavaコードを恐ろしく冗長にして比較するのはそろそろ止めましょうよ。そんなことしても逆に一部では反感を買っちゃうでしょ。そんなことしなくったって、LLはもちろんJavaよりも簡潔に書けるんですから、ひねり技はいりません。そんなことJavaプログラマだって普通に認めてることですから。


だってどっからどうみたってLLのほうが簡潔でしょ。それを抜いてもJavaのほうがいいところがまだあるからJava使ってるんで。


たとえばね。アークランプhttp://www.arclamp.jp/blog/archives/marulec2006_2.html の鈴木さんは私も尊敬する方で実はリンク先の講演も聞いていました。講演は納得感のあるものだったんですよね。設計の幻想に対するアンチテーゼ、つまりは「試行錯誤せずに設計なんかできるか!」ということでLLが人気があるって話なんですよ。なぜLLが流行るのか、という話はブログ界でもあまり見ないように思うので、たいへん興味深いものでした。


でも私はJava技術者なので、例に出てきたコードがあんまりにも冗長だと気になって仕方がないんです。これと比較したら、ガリガリのCコードだってもっと行数短くなるんじゃなかろうか、と思っちゃったんですよ。サンプルはGroovyJavaでしたけど、そのGroovyコードと同じことをJavaでするとき、私だったら絶対そんな冗長な書き方しないんだけど、と思ってしまってそっちに気が取られて5分くらい話を聞いてませんでした。

Groovy

def total = 0
[1..5].each { total += it }
println total

を、Java

import java.util.ArrayList;
import java.util.List;

public class Sample {
  public static void main(String[] args) {
    int total = 0;
    List list = new ArrayList();
    list.add(new Integer(1));
    list.add(new Integer(2));
    list.add(new Integer(3));
    list.add(new Integer(4));
    list.add(new Integer(5));
    for (int i = 0; i < list.size(); i++) {
      total += ((Integer)list.get(i)).intValue();
    }
    System.out.println(total);
  }
}

と書いちゃう人もまあいるかもしれませんが、それはいくらなんでも「短気さ」が足りないんでは。

普通この程度のコードは書くでしょ。

public class Sample {
    public static void main(String[] args) {
        int total = 0;
        int[] list = {1,2,3,4,5};
        for( int i : list) {
             total += i;
        }
        System.out.println(total);
    }
}

さっきよりはるかに簡潔でしょ。でもこれ、私だったらこう書きますよ。

public class Sample {
    public static void main(String[] args) {
        int total = 0;
        for( int i : new int[]{1,2,3,4,5}) {
             total += i;
        }
        System.out.println(total);
    }
}

配列をただループするだけならその場で配列を作ればいいわけで。さらに言えば私のように「forループのブラケットは必ず書く」と決めているような人は上のように書くでしょうけど「必要ないブラケットは書かない」という人は、普通に(無意識に)次のように書くでしょうね。

public class Sample {
    public static void main(String[] args) {
        int total = 0;
        for( int i : new int[]{1,2,3,4,5}) total += i;
        System.out.println(total);
    }
}

ほら、mainメソッドの実装部分は3行になっちゃった。


でも型を必ず宣言しなくちゃいけなかったり、コードはメソッドの中にしかかけない上にメソッドはクラスの中にしかかけなかったりして、やっぱりそれでも4行ほど冗長な部分が残ります。どうしたって言語仕様的にLLの簡潔さにはかなわないんだから、まっとうなJavaコードに対して真っ正面からLLをぶつければいいんですよ。上みたいに最適化したJavaコードに真っ正面からぶつけたって、コードの簡潔さに関してはLLが勝ちますよ。


上の最後のJavaコードを見た上で

def total = 0
[1..5].each { total += it }
println total

このコードの方がもっと簡潔だ、と言っても反対する人なんていないですから。だいたい重要なのは行数じゃなくて、eachに関数クロージャ)を引数で渡してるってところなわけですし。処理と構造をまとめて書いちゃうところなんですし。


だから、そろそろLLを褒めるのにJava(の表現力)を貶めるようなコードを参考として示すのは止めませんか? 雑誌とか、ブログとか。


あ、ちなみにアークランプさんを引き合いに出したのはたまたま私が講演を聞いてて、その参考ソースを見たことがきっかけだったってだけです。アークランプさん自身はJavaの開発や講演や雑誌記事執筆などされてる方ですし、おそらく重々分かった上で講演上分かりやすくなる方法を取ったんだろうなあ、程度に思ってます。あしからず。


[追記]

今回は配列をループするコードということで書いてますが、「1から5をループして合計しろ」だったら普通のJavaプログラマなら素直に下記のようにforのインデックスを使うでしょうね。

public class Sample2 {
    public static void main(String[] args) {
        int total = 0;
        for(int i = 1; i < 6; i++) total += i;
        System.out.println(total);
    }
}

itit 2006/12/17 15:01 何か,どっちのコードを見ても違和感を覚えてしまいますね.
Java にしてもあんな書き方はしないだろーって思うし,
LL なら (Groovy 分かんないんで Ruby で失礼します),
 puts (1..5).to_a.inject(0) {|total, i| total + i }
って書くんじゃないですかね.
というのはともかく.
こういう例での LL の利点はむしろ (m..n) と書けるとこ (Range で配列生成が簡単) だと思ってるんですが.

itit 2006/12/17 15:04 すみません.↑の例,「to_a」要りませんでした.

yusukeyusuke 2006/12/17 15:51 アークランプのゆーすけです。すんません、ブクマに見えたもので勝手に来ちゃいました。
うぐっ(w、あの例はLLを褒めてJavaをけなすというよりも、特徴が違いますねぇというところなのでわかりやすさを重視してまして(汗。言われるとおり、あんなコードは書かないでしょうし、だいたい現場で1から5の配列ループなんて使うわけないので、はい。

itさん、eachもわかりやすさ重視で採用しました。Groovyもinjectは使えます。

ちょっと次回からはサンプルもっとまじめに考えます。Groovyの中の人のデモも同じ感じなので甘えていたのですが。参考にさせていただきます。

yusukeyusuke 2006/12/17 16:05 すみません、しかもウソ書いてました。[1..5].eachは正しく動かないです。eachはListの拡張なのです。RangeになるとeachでRangeそのものが取れちゃいます。ちゃんと試さずに書いたのがいけないです、ごめんなさい。
ちなみに[1..5].each { println it.inject(0,{t,v->t+v}) }ってやると動きます。うーん、微妙だ…

oskimuraoskimura 2006/12/18 01:28 Haskellならこうかきます
print $ foldr (+) 0 [1..5]

wraith13wraith13 2006/12/19 21:55 >そろそろRuby/PythonのようなLLを褒めるのにJavaを貶めるのは止めません?

ビャーネ先生が聞いたら「お前らがそれを言うか?」って突っ込まずにはいられないお言葉ですねw

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証