下記のエントリ
が気になったというか、色々言いたいことあったけど、コメントに書ききれないし、ついでに色々Pimp my Libraryについて説明したりしてしまおう的な
まず結論からいうと、継承もProxyも使う必要なくね?っていう意見
いや、(色々とその後の拡張性とか考えると)使ってはいけないと言うつもりもないんですが。そもそも、元ネタのエントリで、Pointクラスの実装や、どういう使い方をするClassなのかが示されてないのでどうしようもないというか、かってに予想というか、仮定して話進めるしかないのであれ(´・ω・`)
Pointクラスが下記のどれなのか?によって話も変わってくる
- java.awt.Point
- なにかの(外部の)ライブラリのClass
- 自作した(自分で手を加えようと思えば、変更できる)Class
まぁとりあえずそこは置いておいて、自分がどういう実装を思いついたか?っていうのをまず書いてみる
implicit def toRichPoint(p:Point) = new{ def +(other:Point) = new Point( p.x + other.x , p.y + other.y ) }
+というメソッドを追加したいだけなら、上記のようにpimp my libraryパターンで、あえてclass作って継承する必要ないのではないか?と。
pimp my libraryという名前を聞いたことない人が多いと思いますが、Scala作者のodersky先生本人が使っている(というか最初に言い出したのか?あまり詳しい経緯しらない)し、標準ライブラリでも、RichIntなどをはじめ、ある程度使われています。海外のScalaistのなかでも普通に使われているみたいだし、パターンに名前が付いていていて共通理解があったほうが、話すときに便利なので、個人的にこの言葉もっと広まったほうがいいなーと思ってます。
上記のコードでは無名クラスにしてしまいましたが、下記のように
implicit def toRichPoint(p:Point) = new RichPoint(p.x,p.y) class RichPoint(x:Int,y:Int){ def +(other:Point) = new Point( this.x + other.x , this.y + other.y ) }
RichPointという名前を付けておくこともできます。
で、どっちがスタンダードなんですかね?個人的には、上記の方が好きです。*1理由として
- Classの使用箇所や、意図がわかりやすい。(別のクラスになってると、このクラス他の場所でも使われているのか?と考えなくてはいけない)
- そもそもClassの名前考えるのさえめんどくさい(やりたいことしては単に、「Rubyのオープンクラス的に、あとからメソッド追加」なので。変換するために一時的に使われるClassに名前必要なの?という)
からです。やってることというか、実際行われることに違いはないと思います*2
無名にしたほうがいいのか?については、以前にtwitter上でこんなことが
URL MergeableEitherってclassは、mergeっていうメソッドをimplicit conversion使って呼ぶためだけにあるっぽい?だとしたら、無名クラスでよくね? #scala
2011-05-06 14:19:54 via web
MergeableEitherで、ライブラリとコンパイラのソースgrepしたら、明示的にnewしてる部分なんてありませんでしたよっと
2011-05-06 14:22:09 via web
@xuwei_k その部分をscaladoc化した時のことを考えると、無名クラスよりは名前が付いてる方が良いのではないかと。 #scala
2011-05-06 14:32:49 via Tween to @xuwei_k
scaladoc何も書いてないよ\(^o^)/ ・・・・ scala.Either.MergeableEither URL
2011-05-06 14:37:43 via web
今までソースコードよんだ限りの自分の知識では、標準ライブラリ中では無名ではなく名前ついている場合が多いように思います。*3どちらがいいのか(もしくは、どちらでもいいのか?)、何か使い分けの基準が既に存在するのか?情報や意見求む
追記: 無名にした場合と名前つけた場合の違いをコメントにてokomokさんに教えていただきました!ありがとうございますm(_ _)m
たしかに、無名にするとリフレクション呼び出しになってしまうので、パフォーマンスが低下しますね(どの程度低下するかは測ってない)
一度scalacでコンパイルして、jadでjavaコードに逆コンパイルすると以下のようになってました*4
Classに名前つけた場合
private final Point a = toRichPoint(new Point(1, 2)).$plus(new Point(3, 4));
無名の場合
reflMethod$Method1( qual1.getClass()).invoke(qual1, new Object[]{new Point(3, 4)}) )
java.lang.ref.SoftReferenceでMethodオブジェクトをキャッシュしていたり、色々Scalaのコンパイラさんは頑張ってますね。
なんだが、元ネタの話と関係なくなってきて、Pimp my Libraryについての自分の疑問点をつらつらと書きだすエントリになってしまいました(´・ω・`)
話戻して、元エントリに対しては(たいして重要じゃないけど)もう1つだけ言いたいことがあって、
「Richなんとか」っというClass名は、上記のよう形式で、Pimp my Libraryのために付ける場合が(Scalaの慣習的に)多い?から*5違う名前のほうがいいんじゃないか?ということ。
だからと言って自分はいい名前思いつかないんですが(´・ω・`)
繰り返しますがそのあたりは、
- Pointクラス継承したクラスを他にもつくる可能性があるのか?(子クラス複数つくってポリモーフィズムとか必要なの?)
- 継承してなにがしたいのか?
によると思うのですが
*1:というか、どっちもpimp my libraryって言っていいのか?どちらかの場合だけを、pimp my libraryというのか?その辺の共通理解はあるのか?
*2:なにか重要な違いあるなら誰か突っ込んで > <
*3: 役に立つかどうか知らないが、2.8.1で、「implicit」というキーワードで単純にGrepしたもの https://gist.github.com/959360
*4: ちなみにversion2.8.1 でも 2.9.0.1でも同様に無名の方はリフレクション呼び出しになった。gistに載せたのは2.8.1の結果
*5: たとえば、Scala time とか典型的な例