Blog

RubyistがScalaを勉強した話(続き)


前の記事で、ScalaRubyistがよく使っていたActiveRecordパターンを実現しました。

今回は私がよく使っているDuck Typingについて話させて頂きます。

Duck Typing とは

“If it walks like a duck and quacks like a duck, it must be a duck”

(もしもそれがアヒルのように歩き、アヒルのように鳴くのなら、それはアヒルである)

Rubyでは、Duck Typingを使って、「インターフェースを渡す」ことが多いです。

例えば:

 

このコードを見て分かる通り、printという「インターフェース」が存在するものであれば、なんでもUserに渡せます!

ここでDuck Typingはどこが良いかというと、メソッド間で渡すものが「何」じゃなくて、「何ができる」を重視するところです。

つまり、型の依存性を無くして、コードの疎結合を実現できると考えられます。

「せっかく型言語なのに、型の依存性がなくなるのではよくないぞ!」と思っていた方もいらっしゃるかもしれないですが、よく考えてみると、関数型の意味では「処理を重視する」ためのものなので、Duck Typingは悪くないでしょう。

Martin Odeskyインタビュー記事で、Martin氏がDuck Typingについて

Translated, if it has the features that I want, then I can just treat it as if it is the real thing.

(言い換えるならば、もし実装したい機能があるのであれば、その機能として実装することができる)

つまり、Duck Typingにより、Scalaの表現力を高めることできると書かれています。

ScalaDuck Typingの実現

Structural type

なんと凄い簡単にScalaDuck Typingを実現することができます!

 

上のコードを見ると、advertiseがあるものであれば、なんでも受け取るadvertiseWithメソッドがあります。

そのメソッドに渡すものにより、処理を変えることができます!すごいですね!

メソッドを持っていないものを渡してみると

 

ちゃんとコンパイル時に発見できました。

さすが便利ですね、Type SafeDuck Typingは最高

 Pimp my Library

上の例を見て、Duck Typingのどこが有用かと考えてみると、Javaでよく使われているStrategy パターンの実現がすごい楽になります。

「インターフェースからオブジェクトを認識する」という意味だと、インターフェースをパラメータとして渡すだけではなくて、Scalaでは [Pimp My Library](http://www.artima.com/weblogs/viewpost.jsp?thread=179766)という面白いパターンがあります。

そのパターンでは、オブジェクトのインターフェースを用いて、implicit conversionを行ったら、既存のクラスにメソッドを追加することができます。Duck Typingとはちょっと別の概念ですが、「インターフェースから対象オブジェクトを認識できる」という意味だと関連性があると考えられますので、紹介させていただきます。

まずは以下のコードをご覧ください。

 

コードを読むだけで多分何を意味するかをわかると思います。

implicitメソッド+ structural typeの組み合わせで、既にあるクラスを自由にメソッドを追加することができます!

上の例だと Intのタイプに doubleのメソッドを追加することができます。

何か分かりづらいなと思う方もいらっしゃると思いますが、実際はScalaコンパイラが勝手に

から

に変換してくれるだけです!

ここで何が嬉しいかというと

  レガシーコードを触らなくても良くて、別のモジュールにレガシーモジュールの機能を追加することができます

  – Mixinが簡単にでき、デザインパターンでよく言われている:「Composition over inheritance」を簡単に実現できます

やっぱりScalaはすごいFlexibleな言語ですね!

パフォーマンス面

これで十分Structural Typeの便利さを理解して頂いたと思いますが、Structural Typeの大きいデメリットが一つ存在します。それはパフォーマンスです。

なぜStructural Typeがパフォーマンスに影響を簡単に説明すると:reflectionを使うからです。

簡単なベンチマークを取ってみました。

ベンチマークの対象ですが、一つのサンプルでDuck Typingを使って、残りのサンプルは普通にtraitを使います。

結果は。。。

なんと凄い結果。。

こんなにパフォーマンスが悪いことが分かりますが、じゃ、

設計ミスで、既存で、触りたくないライブラリに機能追加したい

パフォーマンスがそんなに重要じゃないところ、あるいは、ボトルネックじゃないところ

つまり、「設計」対「パフォーマンス」のトレードオフをよく考慮して、structural typeを使うべきかと考えます。

Martin Odesky氏の論文にもstructural typeのパフォーマンス周り色々な場面からベンチマークを行ったので、

興味がある方は是非ご参考ください。

http://infoscience.epfl.ch/record/138931/files/2009_structural.pdf

次回には、scalaのオペレーターオーバライドを用いて、なにか面白いプログラミングを作りたいと思いますので、

是非お楽しみにしてください。

DSC03924 2

 

Copyright about logo
Copyright (C) 2008 合同会社Rubyアソシエーション
Copyright (c) 2002-2015 EPFL

Author

アバター
admin