トップ 最新 追記

Onion開発日記

2004|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|

ToDo:


2006-02-01

_ [Java]JavaでMixinもどき

プログラマー日記の1/31/31のエントリより引用:

見ればわかりますが、ただの委譲です。今回の例ならこれで済んじゃうので、もっとこう、ただの委譲じゃ実現できないことが実現できるぞという例がみたいです。

こんな感じでいかがでしょうか。RubyのEnumerableのようなものをJavaで実装してみました。これだと単なる委譲では実現するのは面倒だと思います。 あと、MyListのフィールドmixinをEnumerable型を引数に取るuseEnumerableに渡している所にも注意してください。

import java.util.*;
public class UseMixin {
  //Enumerableを使って何かする
  static void useEnumerable(Enumerable<Integer> enumerable){
    //全部の要素を出力する
    enumerable.each(new Procedure<Integer>(){
      public void call(Integer arg){
        System.out.println(arg);
      }
    });

//リストの全ての要素を2倍する List<Integer> list = enumerable.collect(new Function<Integer, Integer>(){ public Integer call(Integer arg){ return arg * 2; } }); System.out.println("list = " + list);
//リストの各要素の和を計算する int sum = enumerable.inject(0, new Function2<Integer, Integer, Integer>(){ public Integer call(Integer arg1, Integer arg2){ return arg1 + arg2; } }); System.out.println("sum(1..10) = " + sum); }
public static void main(String[] args){ MyList<Integer> nums = new MyList<Integer>(); for(int i = 1; i <= 10; i++){ nums.add(i); } useEnumerable(nums.mixin);//((Enumerable)nums)に相当 } }
interface Function<T, R> { R call(T arg); }
interface Function2<T1, T2, R> { R call(T1 arg1, T2 arg2); }
interface Procedure<T> { void call(T arg); }
//変更可能なT型の値を作るためのクラス class Mutable<T> { T value; Mutable(T value) { this.value = value; } }
abstract class Enumerable<E> { abstract void each(Procedure<E> proc);
<R> List<R> collect(final Function<E, R> func){ final List<R> list = new ArrayList<R>(); each(new Procedure<E>(){ public void call(E e){ list.add(func.call(e)); } }); return list; }
<R> R inject(final R init, final Function2<E, R, R> func){ final Mutable<R> var = new Mutable<R>(init); each(new Procedure<E>(){ public void call(E e){ var.value = func.call(e, var.value); } }); return var.value; } }
//Enumerableを使用EnumerableをMixin class MyList<T> extends ArrayList<T> { Enumerable<T> mixin = new Enumerable<T>(){ //collectとinjectは実装しなくてOK public void each(Procedure<T> proc){ for(T t : MyList.this){ proc.call(t); } } }; }

出力結果:

1
2
3
4
5
6
7
8
9
10
list = [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
sum(1..10) = 55
本日のツッコミ(全4件) [ツッコミを入れる]

_ nt [なんかしらんけどすごいな. mix-inって要するにどういう目的の概念なん? ]

_ maeda [nums.mixinよりnums.asEnumerable()の方が良くない? んで、asEnumerable()を..]

_ みずしま [> nums.mixinよりnums.asEnumerable()の方が良くない? 確かにそうですね。mixinが..]

_ みずしま [ntさん > mix-inって要するにどういう目的の概念なん? 返事遅くなってごめん。一言で言うと、クラスの多重継..]

本日のリンク元 | 50 | 18 | 17 | 6 | 4 | 4 | 3 | 3 | 2 | 2 | TrackBack(0)

2006-02-02

_ [Java]続・JavaでMixinもどき

maedaさんからのツッコミがあったので、それを受けて 昨日の例を改良してみた。また、ただ改良するだけでは面白くないので、Fileクラスを継承したクラスにもMixinしてみた。

import java.io.*;
import java.util.*;

public class UseMixin { //ディレクトリ直下のファイルサイズの合計を調べる static long sumSize(EnumerableSrc<File> src){ return src.asEnumerable().inject(0L, new Function2<File, Long, Long>(){ public Long call(File f, Long r){ return f.length() + r; } }); }
//ファイルサイズとファイル名をつなげた文字列のリストを返す static List<String> fileSizeAndNames(EnumerableSrc<File> src){ return src.asEnumerable().collect(new Function<File, String>(){ public String call(File f){ return "ファイルサイズ: " + f.length() + " バイト\t" + "ファイル名: " + f.getName(); } }); }
public static void main(String[] args){ EnumerableFile file = new EnumerableFile("."); System.out.printf("合計サイズ: %d%n", sumSize(file)); for(String s : fileSizeAndNames(file)) System.out.println(s); } }
//1引数の関数を表すインタフェース interface Function<T, R> { R call(T arg); }
//2引数の関数を表すインタフェース interface Function2<T1, T2, R> { R call(T1 arg1, T2 arg2); }
//1引数の手続きを表すインタフェース interface Procedure<T> { void call(T arg); }
//変更可能なT型の値を作るためのクラス class Var<T> { private T value; private Var(T value) { this.value = value; } public T value() { return value; } public void value(T value) { this.value = value; } public static <T> Var<T> ref(T value){ return new Var<T>(value); } }
interface EnumerableSrc<T> { Enumerable<T> asEnumerable(); }
abstract class Enumerable<E> { abstract void each(Procedure<E> proc);
<R> List<R> collect(final Function<E, R> func){ final List<R> list = new ArrayList<R>(); each(new Procedure<E>(){ public void call(E e){ list.add(func.call(e)); } }); return list; }
<R> R inject(final R init, final Function2<E, R, R> func){ final Var<R> var = Var.ref(init); each(new Procedure<E>(){ public void call(E e){ var.value(func.call(e, var.value())); } }); return var.value(); } }
//ディレクトリの要素を列挙可能なFile class EnumerableFile extends File implements EnumerableSrc<File> { EnumerableFile(String path){ super(path); } private Enumerable<File> enumerable = new Enumerable<File>(){ //collectとinjectは実装しなくてOK public void each(Procedure<File> proc){ for(File f : EnumerableFile.this.listFiles()){ proc.call(f); } } }; public Enumerable<File> asEnumerable() { return enumerable; } }

実行結果:

合計サイズ: 11371
ファイルサイズ: 819 バイト      ファイル名: Enumerable$1.class
ファイルサイズ: 841 バイト      ファイル名: Enumerable$2.class
ファイルサイズ: 1006 バイト     ファイル名: Enumerable.class
ファイルサイズ: 652 バイト      ファイル名: EnumerableFile$1.class
ファイルサイズ: 609 バイト      ファイル名: EnumerableFile.class
ファイルサイズ: 235 バイト      ファイル名: EnumerableSrc.class
ファイルサイズ: 255 バイト      ファイル名: Function.class
ファイルサイズ: 301 バイト      ファイル名: Function2.class
ファイルサイズ: 217 バイト      ファイル名: Procedure.class
ファイルサイズ: 777 バイト      ファイル名: UseMixin$1.class
ファイルサイズ: 967 バイト      ファイル名: UseMixin$2.class
ファイルサイズ: 1536 バイト     ファイル名: UseMixin.class
ファイルサイズ: 2528 バイト     ファイル名: UseMixin.java
ファイルサイズ: 628 バイト      ファイル名: Var.class
本日のリンク元 | 19 | 14 | 9 | 6 | 4 | 3 | 3 | 3 | 2 | 2 | TrackBack(0)

2006-02-05

_ [Java]無名クラスから外側のスコープのローカル変数を変更する

Javaでは、無名クラスから外側のスコープのローカル変数にアクセスする場合、final修飾子をつける必要がある、つまり、無名クラスから外側のスコープのローカル変数を変更することはできない。多くのケースでは、ローカル変数の値を変更しなくてもなんとかなるので、困ることは案外少ない。しかし、ときどき無名クラスから外側のスコープのローカル変数にアクセスしたい場合もある。そこで、どのようにしてそのようなことを実現すれば良いかというのが今回のお話。

要点は、変更できないのは「ローカル変数」であって、ローカル変数の 値となっている「オブジェクト」自体は変更可能であるということだ。

案1: 配列を使う

変更したいローカル変数をあらかじめ配列として宣言しておくという方法。 配列はJavaに最初から組み込まれているので手軽に扱えるという利点があるが、何のために配列を使っているのか、コードをぱっと見ただけでは把握しにくいという欠点がある。

class Main {
  public static void main(String[] args){
    final boolean[] var = new boolean[]{false};
    System.out.printf("var: %s%n", var[0]);
    new Runnable(){
      public void run(){
        var[0] = true;
      }
    }.run();
    System.out.printf("var: %s%n", var[0]);
  }
}
実行結果:

var: false var: true

案2: クラスを使う

変更したい型の値をラップするクラスを作り、無名クラスからはそのオブジェクトを経由して変数の値を参照するという方法。適切なクラス名を付けることによって、意図が伝わりやすくなる(かも)というのが利点だが、配列を使う場合に比べて、クラスを1つ余計に定義する必要があるのが欠点か。

//Boolean型の値をラップするクラス
class BooleanVar {
  boolean value;
  BooleanVar(boolean value){
    this.value = value;
  }
}

class Main { public static void main(String[] args){ final BooleanVar var = new BooleanVar(false); System.out.printf("var: %s%n", var.value); new Runnable(){ public void run(){ var.value = true; } }.run(); System.out.printf("var: %s%n", var.value); } }

Java5で導入されたGenericsを使えば、次のように型に依存しない形でラップ用のクラスを定義することもできる。これならクラスは一度だけ定義しておけばいいので、随分楽だ。

//任意のT型の値をラップ可能なクラス
class Var<T> {
  T value;
  Var(T value){ this.value = value; }
}

class Main { public static void main(String[] args){ final Var<Boolean> var = new Var<Boolean>(false); System.out.printf("var: %s%n", var.value); new Runnable(){ public void run(){ var.value = true; } }.run(); System.out.printf("var: %s%n", var.value); } }

Var型のオブジェクトを生成するときに、new Var<T>(value)のようにするのが面倒ならば、次のようにGenericメソッドを使って簡略化することもできる。

class Var<T> {
  T value;
  Var(T value){ this.value = value; }
  //Genericメソッド
  static <T> Var<T> ref(T value){ return new Var<T>(value); }
}

これならいちいちnew Var<T>(value)のようにしなくても、Var.ref(value)とするだけで良い。

class Main {
  public static void main(String[] args){
    final Var<Boolean> var = Var.ref(false);
    System.out.printf("var: %s%n", var.value);
    new Runnable(){
      public void run(){
        var.value = true;
      }
    }.run();
    System.out.printf("var: %s%n", var.value);
  }
}

さらに、Java 5で導入されたstatic importを使えば、もっと簡略化することができる。ちなみに、このプログラムでpackage宣言をしているのは、static importで無名パッケージのクラスのstaticメソッドを取り込むことができなかったためだ。

package example;

import static example.Var.*;
class Var<T> { T value; Var(T value){ this.value = value; } static <T> Var<T> ref(T value){ return new Var<T>(value); } }
class Main { public static void main(String[] args){ final Var<Boolean> var = ref(false); System.out.printf("var: %s%n", var.value); new Runnable(){ public void run(){ var.value = true; } }.run(); System.out.printf("var: %s%n", var.value); } }

_ [言語]「elispを作る」?

Webページを見ていると、Emacs Lispのプログラムを作ることを指して、「elispを作る」や「Emacs Lispを作る」、あるいは作ったEmacs Lispのプログラムのことを指して「elisp」や「Emacs Lisp」と書いているのをときどき見かけるのだが、これは何故なのだろうか?他の言語、例えばJavaやRubyのプログラムを作ることを指して「Javaを作る」、「Rubyを作る」とは言ったりしないと思うのだが。

本日のツッコミ(全11件) [ツッコミを入れる]

Before...

_ free online blackjack  [Z1NTkMpe6K@msn.com ]

_ party poker bonus  [3G67LP@yahoo.us ]

_ free texas holdem poker game  [QVW4RRn@msn.com ]

_ qzghvft cpldswf [teuapyd veji vjahw yahz jptefhlmw gyvqzolpb ockzla ]

_ pyvl biqyjv [lsqaucmpb pritvo qhzcfwot nfreiz qpjnm bjkwp bhnfos ]

本日のリンク元 | 15 | 15 | 13 | 11 | 10 | 9 | 8 | 8 | 5 | 5 | TrackBack(0)

2006-02-06

_ [Java]Java 5.0のコードを1.4のVMで動作させる

A Diary Which Heads for Convergence (Naist branch)より。

javacの-targetオプションでjsr14と指定すれば、Java 5.0の機能を使ったソースコードをコンパイルしたコードが1.4のVM上で動作するようだ。早速試してみたところ、確かにコンパイルしたコードを1.4のVMで動作させることができた。非公開オプションのようだが、Java5.0の機能を使ったソースコードを1.4で動作させたい場合には使えるかもしれない。

追記:当たり前だが、Typesafe Enumのように5.0で新しく追加されたAPIを使っている場合は実行できない。Generics、static improt、拡張for文などは新しいAPIを使っていないので、動作する。

_ [Java][言語]DI Containerを言語レベルで

ナンセンス不定記より引用。

javaでインスタンスを生成する際に、実装クラスをnewするのではなく、インターフェイスをnewする。
・・・
DIコンテナをひとつの外部ライブラリとするのではなく、言語実装の一部とする。つまり、DIは空気のようなもの。

これは面白いかも。元の話と動機は少し違うが、

List list = new ArrayList();

のようなコードを書くときって、大抵の場合、実装クラスがArrayListであるっていうのはどうでもいいのであって、そういうときに

List list = new List();

のように書けると気持ちよさそう。

もしないのなら、これこそすぐにJavaSEレベルで欲しい機能だと思うんだけどね。

Javaに導入するのは、既存のソースコードの互換性を保て無さそうなので、難しいのではないだろうか。

本日のツッコミ(全18件) [ツッコミを入れる]

Before...

_ party poker download  [zLBzxAiS@yahoo.com ]

_ free pacific poker  [qfiL4A@gmail.com ]

_ free texas holdem poker game  [CtSsZUm@yahoo.com ]

_ progressive slots  [AS9N013VfV@gmail.com ]

_ free casino slots game  [HLlpSqe1Yl@msn.com ]

本日のリンク元 | 203 | 60 | 41 | 24 | 24 | 21 | 15 | 11 | 10 | 9 | TrackBack(0)

2006-02-13

_ [卒論]発表

いよいよ発表。事前に何回も発表練習をして、準備万端…のはずだったのだが、実際に自分の番になると、かなりあがりまくる。おかげで、次のスライドへのつなぎの言葉を言うときに、間違えて次の次のスライドへのつなぎの言葉を言ってしまうという大ポカをやらかしてしまった。

ともあれ、発表も無事(?)終わって、ほっとした。これで自分にとっての大学関連の行事はほとんど終わったことになる。

本日のツッコミ(全2件) [ツッコミを入れる]

_ ささだ [おつかれー。 ]

_ みずしま [遅くなりましたが、どうもありがとうございます。 プレゼンの出来は今一つでしたが、とりあえず終わって ほっとしました。..]

本日のリンク元 | 1 | 1 | 1 | 1 | TrackBack(0)

2006-02-15

_ [ジョギング]3km,23分

約2ヶ月ぶり。さすがにこれだけ間が空くと、かなり体力が落ちてしまうようで、なかなかしんどかった。しかし、懸念していた右膝の痛みは再発しなかったので、ほっとした。

_ [Groovy]Groovy JSR-05 released

こんな毎日・・・ Script_on_Java経由。

Warning: there is an important change in scripts between "def-ed" variables and not "def-ed" variables. Defining a variable with the def keyword or with a concrete type creates a local variable which won't be stored in the binding. However, if you assign a variable which wasn't defined in your script, it will be stored in the binding of the script.

というのが気になる。defで宣言した変数は、Java VMのローカル変数を使って実装されるということだろうか?

本日のツッコミ(全18件) [ツッコミを入れる]

Before...

_ party poker bonus  [OrrOK4@yahoo.us ]

_ free internet poker  [gRyKTjYk@yahoo.us ]

_ play free slots  [O5QUK@msn.com ]

_ free casino slots game  [opQGK3s1t@operamail.com ]

_ jdw6d13@yahoo.com [funny ringtones]

本日のリンク元 | 20 | 9 | 7 | 6 | 4 | 3 | 3 | 3 | 2 | 2 | TrackBack(0)

2006-02-16

_ [デザインパターン]ファクトリーメソッド

ファクトリーメソッドと言うと、すっかり「単にインスタンスを生成するメソッド」という意味になってしまった感があるのだが、何故こうなったのだろうか。「ファクトリーメソッド」の出典と思われるGoF本では、単にインスタンスを生成するメソッドのことをファクトリーメソッドと呼んでいたわけではないはずなんだけど。

まあ、ファクトリーメソッドを単にインスタンスを生成するメソッドという意味で使っても、それ自体は大して困ったことでは無いかもしれない。しかし、「ファクトリーメソッド」とGoFの「ファクトリーメソッドパターン」を混同して、「ファクトリーメソッドパターン」を単に「インスタンスを生成するメソッドを使うパターン」の意味で使うのはどうかと思う。

_ [Groovy]"def-ed" Variables and not "def-ed" Variables

2/15のエントリで書いた件が気になったので、ちょっと調べてみた。 まずは、変数宣言にdefをつけた場合。

プログラム

def x = "Hello"
x

逆アセンブル結果

public java.lang.Object run();
  Code:
   0:	ldc	#51; //String Hello
   2:	astore_1
   3:	aload_1
   4:	areturn

次は、変数宣言にdefをつけない場合。

プログラム

x = "Hello"
x

逆アセンブル結果

public java.lang.Object run();
  Code:
   0:	ldc	#51; //String Hello
   2:	dup
   3:	aload_0
   4:	ldc	#53; //String x
   6:	invokestatic	#57; //Method org/codehaus/groovy/runtime/ScriptBytecodeAdapter.setGroovyObjectProperty:(Ljava/lang/Object;Lgroovy/lang/GroovyObject;Ljava/lang/String;)V
   9:	pop
   10:	aload_0
   11:	ldc	#53; //String x
   13:	invokestatic	#61; //Method org/codehaus/groovy/runtime/ScriptBytecodeAdapter.getGroovyObjectProperty:(Lgroovy/lang/GroovyObject;Ljava/lang/String;)Ljava/lang/Object;
   16:	areturn

これらの結果を見ると、"def"を付けた変数はJava VMの通常のローカル変数として保存され、"def"を付けない変数はオブジェクトのプロパティとして保存される、ということのようだ。

本日のリンク元 | 16 | 8 | 6 | 5 | 5 | 3 | 3 | 3 | 2 | 2 | TrackBack(0)

2006-02-18

_ [Java]Yahoo!テキスト翻訳で「ぬるぽ」を日⇒英翻訳すると・・・

オレンジニュース経由。Yahoo!テキスト翻訳で「ぬるぽ」を日英翻訳すると…という話題。早速、「ぬるぽ」と入力して試してみたところ、「ガッ」と表示された。よくやるなあ(笑)。ところで、こういうのもイースターエッグと言うのだろうか。

追記:Excite翻訳でも、同じことを試してみたが「ぬるぽ」のままだった。残念。

_ [Groovy]再帰関数をクロージャとして定義する

という話題がgroovy-user MLにあった。とりあえず今のバージョンだと、こんな感じで書けるようだ。

def fact = {x ->
  if(x < 2) return 1 else return n * this.call(x - 1)
}

ただ、groovy-user MLでの情報によると、1.0までにクロージャ中のthisの仕様が変わるらしく、このコードは将来的には動かなくなるらしい。解決するには、次のようにすればいいとのこと。

def fact = {}
fact = {x ->
  if(x < 2) return 1 else return n * fact(x - 1)
}

再帰関数を定義する前に、代入する変数を宣言して初期化しているのがポイント。次のようにした場合、クロージャ中のfactの呼び出しでエラーになってしまう。

def fact = {x ->
  if(x < 2) return 1 else return n * fact(x - 1)
}
本日のツッコミ(全2件) [ツッコミを入れる]

_ ojli hwvrbsou [fzey lwzpaqvio zhqranl qwhren hpdyzxigs ybdqg qvln ]

_ jdw6d13@yahoo.com [funny ringtones]

本日のリンク元 | 35 | 24 | 14 | 12 | 8 | 7 | 7 | 7 | 7 | 6 | TrackBack(0)

Mizushima Kota/e-mail: i021216{at}coins.tsukuba.ac.jp/SKype ID: mizu_standard