2012年7月8日日曜日

GroovyのmetaClass.defineでインターフェースメソッドをオーバーロードしたいんだけど

寒いですね。このままだとかき氷屋が倒産してしまいますね。

かき氷屋が倒産する→シロップメーカーが倒産する→サトウキビ売れなくなる→沖縄の人困る

いやですね。

みけです。

メソッドをオーバーロードしたいなぁ


グルービー語をやっている人は常々こういう欲求に駆られてしまい、

いつの間にかメソッドをオーバーロードしていることがあります。

たとえば、Integerを単純に表示するだけでは面白く無いので、

toStringメソッドにClosure<&Stringgt;を引数で取るようにして、

出力を変えてみたいと思ってしまいます。

Javaでやると、こいつは大変で、Integerの持っていた計算性を失って、

拡張するという覚悟を取らなければなりませんが、Groovyでは、

Integerの可算性を損なわずに拡張できます。






並行処理プログラミング


まあ、さっきのはどうでもいいんですよ。

事の本質は並行処理プログラミングの話です。

昨日のCSPモデルをjava.util.concurrentを使って模してみた

プログラムを普通に書いてみました。

ちなみに仕様としては

  • 0~9のランダムの数値をスレッド間で送受信する
  • 0が二回連続して送信されると終了する
  • 送受信が終了すると、これまで送受信された数値の合計が返される

といったものです。




…長いですね。

で、嫌なところは、17行目などにあるnew Callable<Integer> @Override Integer call()

といったあたりですね。

非常にまどろっこしいです。

なので、本当はこう書きたいんです。



ExecutorServiceのメソッドsubmitが引数にクロージャーを取れるように

すれば、なんと7行もコードが短くなるんです。

まあ、Java8になれば、おkなんですがね。



グルービスト


Java8まで待てないということもあるので、

そういう場合のグルービストはこんなことをやるのです。



さて、拡張したExecutorServiceを読んでみるとこうなります。




あれ、値が…


値が戻って来ませんね…

とつぶやいているうちにふもさんからアドバイスもらいました。





なるほど、メソッド名がかぶっているとだめなのか…

あれ、でも、さっきのIntegerの場合だとどうしておkなの?

うーんと悩んでいると、えいやさんからこんなアドバイスもらいました。





なるほど、どうやらインターフェースを拡張する場合に発生しうる現象のようですね。

で、インスタンスを得た後に拡張してしまえば、問題ないというわけですね。


簡単にまとめると…


  • インターフェースを拡張する
  • 実装クラスが割り当てられる
  • 実装クラスによって上書き

でも、なんだか腑に落ちませんね。

どうなんでしょう、この動き…

JIRAのイシューでも漁ってみようかな…

1 件のコメント:

  1. 後半の話、ふもさんの解決が来てましたね。
    https://gist.github.com/3065304

    それから私の方でも、幾つかのケースを試してみました。
    https://github.com/aya-eiya/GroovyMetaClassTest

    適当に進めたので、ちょっとごちゃっとしちゃいましたが。。。

    継承の深さとかで変わったりはしないので、引数の型選ぶ時のポリモーフィズムで正しいのが選べていないように見えます。

    返信削除