argius note

プログラミング関連

Rubyの標準ライブラリをPureJavaで書いてみる (1)

これは11/27に書いたものの続きです。

Rubyの記述力の高さをJavaでも実現してみたいので、RubyのつもりでJavaのコードが書けるようなライブラリを作ってみます。既にどこかで同じかそれ以上のものが作られていたりするかもしれません*1が、JavaSE5.0から導入された新しいJava言語機能を使わないと実現が難しいため、副産物としてこれらの新機能についてちょっと勉強になったりしています。
動的言語っぽさを出すためには総称型とオートボクシング/アンボクシングは不可欠ですし、組み込み関数っぽさを出すにはstatic-import機能が手放せません。foreachや可変長引数も捨てがたいですね。無理やり注釈も使ってたりするので、残りはEnumだけです。今のところ使い道が思いつきませんが、たぶん使うことになるでしょう。
成果物については、ある程度形になったら公開するかもしれません。

これはJavaとしてはおそらく邪道な方法です。ネタとしてご覧ください。

現在の状況

  • Enumerable,Arrayが80%程度完成。blockの実現方法はもうちょっと検討したい。
  • Kernel,Range,Str(String),Regexpを作り始める。
  • I/O関連は見送り。やるとしても後回し。
  • 他は今のところJava標準のものを使う。

サンプル

本体は未だ整理できていないので、使い方だけ。

Ruby
array = Array[1, 2, 3]
a = [1, 2, 3]
range = Range.new(1, 3)
r = (1..3)
p array, a, range, r
[3, 4, 5].reverse_each do |item|
  print item
end
puts (1..4).to_a.shift
def collect()
  Proc.new do |item| item * 2 end
end
print a.collect(&collect)
puts
Java+"lib.ruby"
import static lib.ruby.Kernel.*;
import lib.ruby.*;
import lib.ruby.Enumerable.*;

public final class Main {
    public static void main(String[] args) {
        Array<Integer> array = array(1, 2, 3);
        Array<Integer> a = a(1, 2, 3);
        Range<Integer> range = range(1, 3);
        Range<Integer> r = r(1, 3);
        puts(array, a, range, r);
        a(3, 4, 5).reverseEach(new Callable<Integer>() {
            public void call(Integer element) {
                print(element);
            }
        });
        puts(range(1, 4).toA().shift());
        Collectable<Integer> collectable = new Collectable<Integer>() {
            public Integer collect(Integer element) {
                return element * 2;
            }
        };
        puts(a.each(collectable));
    }
}
$ # ruby/java両方
[1, 2, 3]
[1, 2, 3]
1..3
1..3
5431
246
$

*1:潜在的にそれを覚えていて、無意識に作り直しているんじゃないかと疑っています。