Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Rpscala2011 0601

1,458 views

Published on

scala勉強会 渋谷

Scaalでプログラム作ってみたのでScalaの作法を教えてください

  • Be the first to comment

  • Be the first to like this

Rpscala2011 0601

  1. 1. <ul><li>Scala でプログラム作ってみたので </li></ul><ul><li>Scala の 作法を教えてください </li></ul>
  2. 2. 自己紹介 <ul><li>( 株 ) オープンストリーム 所属 </li></ul><ul><li>twitter yangiYa </li></ul><ul><li>COBOL -> Java (-> Scala になれたら。。 ) </li></ul><ul><li>会社ではあまりプログラム作る 機会がなくなってきた。欲求不満 </li></ul><ul><li>Scala は去年の秋ぐらいからはじめた </li></ul><ul><li>Scala の書籍で読んだもの </li></ul><ul><ul><li>Scala プログラミング入門 </li></ul></ul><ul><ul><ul><li>デイビッド・ポラック ( 日経 BP 社 ) </li></ul></ul></ul><ul><ul><li>プログラミング Scala </li></ul></ul><ul><ul><ul><li>Dean Wamloer/Alex Payne ( オライリー ) </li></ul></ul></ul>
  3. 3. <ul><li>作ってみたもの </li></ul><ul><li>の </li></ul><ul><li>説明 </li></ul>
  4. 4. <ul><li>行列モデルを Scala で実装 </li></ul>
  5. 5. 利用用途 <ul><li>行列で表現できる概念に汎用的に利用 </li></ul><ul><li>「物体」 ( ゲームのキャラクタなど ) の座標 </li></ul><ul><li>「物体」の速度 </li></ul><ul><li>「物体」の大きさ </li></ul><ul><li>将棋、囲碁、チェス、オセロ、などの駒の位置 </li></ul>
  6. 6. 要求仕様(モデルの値) <ul><li>座標は、x,y,z </li></ul><ul><li>x,y,z のデフォルトは Double </li></ul><ul><li>平面上のオブジェクト表現の場合は、 x,y だけで管理したい </li></ul><ul><li>x,y,z を整数で管理したい場合もある。 ( 整数同士の計算結果が少数点以下の数字にならないようにしたい) </li></ul>
  7. 7. 要求仕様(モデルのサービス) <ul><li>行列の加算 </li></ul><ul><ul><li>( 2,1 ) + (3,1) = (5,1) </li></ul></ul>
  8. 8. 要求仕様(モデルのサービス) <ul><li>行列の k 倍 </li></ul><ul><ul><li>( 2,1 ) × 3 = (6, 3 ) </li></ul></ul>
  9. 9. インタフェース設計 <ul><li>trait Matrix { </li></ul><ul><li>/**[[scala.Int]] 型の x 座標 */ </li></ul><ul><li>def xByInt: Int </li></ul><ul><li>/**[[scala.Int]] 型の y 座標 */ </li></ul><ul><li>def yByInt: Int </li></ul><ul><li>/**[[scala.Int]] 型の z 座標 */ </li></ul><ul><li>def zByInt: Int </li></ul><ul><li>/**x 座標 */ </li></ul><ul><li>def x: Double </li></ul><ul><li>/**y 座標 */ </li></ul><ul><li>def y: Double </li></ul><ul><li>/**z 座標 */ </li></ul><ul><li>def z: Double </li></ul><ul><li>} </li></ul>
  10. 10. インタフェース設計 <ul><li>/** この行列と引数の行列の和を返却する */ </li></ul><ul><li>def add(matrix: Matrix): Matrix </li></ul><ul><li>def +(matrix: Matrix): Matrix = add(matrix) </li></ul>
  11. 11. インタフェース設計 <ul><li>/** この行列の実数倍 ( 引数 ) を返却する */ </li></ul><ul><li>def product(scalarValue: Long): Matrix </li></ul><ul><li>/** この行列の実数倍 ( 引数 ) を返却する */ </li></ul><ul><li>def product(scalarValue: Int): Matrix </li></ul><ul><li>/** この行列の実数倍 ( 引数 ) を返却する */ </li></ul><ul><li>def product(scalarValue: Double): Matrix </li></ul>
  12. 12. インタフェース設計 <ul><li>/** この行列に実数倍 ( 引数 ) した行列と、この行列との和を返却する */ </li></ul><ul><li>def productValueAndAdd(scalarValue: Long): Matrix </li></ul><ul><li>/** この行列に実数倍 ( 引数 ) した行列と、この行列との和を返却する */ </li></ul><ul><li>def productValueAndAdd(scalarValue: Int): Matrix </li></ul><ul><li>/** この行列に実数倍 ( 引数 ) した行列と、この行列との和を返却する */ </li></ul><ul><li>def productValueAndAdd(scalarValue: Double): Matrix </li></ul>
  13. 13. 要求仕様(非機能) <ul><li>低いオブジェクト生成コスト 頻繁に利用されるバリューオブジェクトを想定 </li></ul><ul><li>スレッドセーフ 複数のスレッドから利用されることを想定 </li></ul><ul><li>利用者インタフェースのみに縛られる </li></ul><ul><ul><li>利用者は具象クラスや内部実装に縛られたくない </li></ul></ul><ul><ul><li>インタフェースを守る範囲で内部実装は自由に変えたい </li></ul></ul>
  14. 14. 非機能要求からの方針 <ul><li>オブジェクト生成コストは小さいほうがいい </li></ul><ul><ul><li>オブジェクトが使うメモリは小さく </li></ul></ul><ul><ul><li>オブジェクト生成時の処理ロジックは少なく </li></ul></ul><ul><li>イミュ ー タブル </li></ul><ul><ul><li>複数スレッドからも安全に使用できる </li></ul></ul><ul><li>インターフェースを維持し、かつ、利用局面に応じた具象クラスを使えるようにする </li></ul><ul><ul><li>オブジェクト生成は、 java の static ファクトリーメソッドのようなイメージで </li></ul></ul><ul><ul><ul><li>(Java の例 ) java.util.Calendar#getInstance() ==>Scala では、 object の         apply メソッドがよさそう </li></ul></ul></ul>
  15. 15. モデル設計 ( 一部抜粋 ) MatrixWithDouble x:Double y:Double z:Double MatrixWithInt xByInt:Int yByInt:Int zByInt:Int MatrixWithInt2D xByInt:Int yByInt:Int zByInt:Int = 0 MatrixWithDouble2D x:Double y:Double z:Double = 0.0 Matrix x:Double y:Double z:Double xByInt:Int yByInt:Int zByInt:Int << インタフェース >>
  16. 16. オブジェクト生成 <ul><li>object Matrix { // ・・・コンパニオンオブジェクトと呼ばれる? </li></ul><ul><li>def apply(x: Int, y: Int, z: Int): MatrixWithInt = </li></ul><ul><li>MatrixWithInt(x, y, z) </li></ul><ul><li>def apply(x: Int, y: Int): MatrixWithInt2D = </li></ul><ul><li>MatrixWithInt2D(x, y) </li></ul><ul><li>def apply(x:Double,y:Double,z:Double): MatrixWithDouble = </li></ul><ul><li>                         MatrixWithDouble(x, y, z) </li></ul><ul><li>def apply(x: Double, y: Double): MatrixWithDouble2D = </li></ul><ul><li>                         MatrixWithDouble2D(x, y) </li></ul><ul><li>} </li></ul>
  17. 17. 機能仕様(=テスト仕様)抜粋 <ul><li>assert(Matrix(1, 2, 3) === MatrixWithInt(1, 2, 3)) </li></ul><ul><li>val mtx10_20_30Double = MatrixWithDouble(1.0, 2.0, 3.0) </li></ul><ul><li>assert(Matrix(1.0, 2.0, 3.0) === mtx10_20_30Double) </li></ul><ul><li>assert(Matrix(1.0, 2, 3) === mtx10_20_30Double) </li></ul><ul><li>assert(Matrix(1, 2) === MatrixWithInt2D(1, 2)) </li></ul><ul><li>assert(Matrix(1.1, 2.2) === MatrixWithDouble2D(1.1, 2.2)) </li></ul>
  18. 18. 機能仕様(=テスト仕様)抜粋 <ul><li>val mtx21_32_0 = MatrixWithInt2D(21, 32) </li></ul><ul><li>assert((Matrix(1, 2) + Matrix(20, 30)) === mtx21_32_0) </li></ul><ul><li>assert(Matrix(20, 30) + (Matrix(1, 2)) === mtx21_32_0) </li></ul><ul><li>val mtx111_222_333 = MatrixWithDouble(11.1, 22.2, 33.3) </li></ul><ul><li>assert(Matrix(10, 20) + Matrix(1.1, 2.2, 33.3) === </li></ul><ul><li>                        mtx111_222_333) </li></ul><ul><li>assert(Matrix(1.1, 2.2, 33.3).add(Matrix(10.0, 20.0)) === </li></ul><ul><li>                           mtx111_222_333) </li></ul>
  19. 19. 機能仕様(=テスト仕様)抜粋 <ul><li>var m1: Matrix = Matrix(1, 2) </li></ul><ul><li>var m2: Matrix = Matrix(10, 20) </li></ul><ul><li>assert(m1 + m2 === MatrixWithInt2D(11, 22)) </li></ul>
  20. 20. 実装:オーバーロードとオーバーライド <ul><li>sealed trait Matrix { </li></ul><ul><li>/** この行列と引数の行列の和を返却する */ </li></ul><ul><li>def add(matrix: Matrix): Matrix = Matrix(x + matrix.x, y + matrix.y, z + matrix.z) </li></ul><ul><li>} </li></ul><ul><li>private[core] abstract trait MatrixWithIntBase extends Matrix { </li></ul><ul><li>def add(point: MatrixWithInt): MatrixWithInt = MatrixWithInt(xByInt + point.xByInt, yByInt + point.yByInt, zByInt + point.zByInt) </li></ul><ul><li>def add(point: MatrixWithIntBase): MatrixWithIntBase = MatrixWithInt(xByInt + point.xByInt, yByInt + point.yByInt, zByInt + point.zByInt) </li></ul><ul><li>} </li></ul>
  21. 21. 実装:オーバーロードとオーバーライド <ul><li>final case class MatrixWithInt2D private[core](xByInt: Int, yByInt: Int) extends MatrixWithIntBase with Matrix2D { </li></ul><ul><li>def add(matrix: MatrixWithInt2D): MatrixWithInt2D = MatrixWithInt2D(xByInt + matrix.xByInt, yByInt + matrix.yByInt) </li></ul><ul><li>def +(matrix: MatrixWithInt2D): MatrixWithInt2D = add(matrix) </li></ul><ul><li>override def add(matrix: MatrixWithIntBase): MatrixWithIntBase = matrix match { </li></ul><ul><li>case pointWithInt2D: MatrixWithInt2D => add(pointWithInt2D) </li></ul><ul><li>case pointWithInt: MatrixWithInt => add(pointWithInt) </li></ul><ul><li>case other => super.add(other) </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
  22. 22. 機能と実装の 説明おわり
  23. 23. もっとやるとしたら (今回やってません) <ul><li>機能要求 </li></ul><ul><ul><li>行列の回転 </li></ul></ul><ul><li>非機能要求 </li></ul><ul><ul><li>Flyweight パターン </li></ul></ul><ul><ul><li>オブジェクトキャッシュ </li></ul></ul>
  24. 24. 感想 と 知りたいこと
  25. 25. 感想 - Scaladoc class と object が横並び コンストラクタを private に したら表示されない リンクはもっと柔軟にかけたらいいのに
  26. 26. Scaladoc リンクはもっと柔軟にかけたらいいのに <ul><li>[[ クラス名フル修飾 ]] でリンクになる </li></ul><ul><ul><li>パッケージ名を書くの面倒。 import されているのは、シンプルなクラス名だったらいいのに </li></ul></ul><ul><li>メソッドへのリンクつくれないの? なんか方法ないですか。おしえてください </li></ul><ul><li>Scaladoc 文法を書いてあったページが なくなっているような。。。 (Scaladoc 2 Documentation for Authors) </li></ul>
  27. 27. Scaladoc コンストラクタを private にしたら表示 されない <ul><li>private コンストラクタが表示されないことは うれしい </li></ul><ul><li>利用者に、どうやってインスタンス化するかは、ドキュメントに書くしかないか? </li></ul><ul><ul><li>誰もが迷うことなくインスタンス化する方法を 把握できればいいのに。 いい方法ないでしょうか。 </li></ul></ul>
  28. 28. Scaladoc class と object が横並び <ul><ul><li>コンパイルした結果の </li></ul></ul><ul><ul><ul><li>&quot;class Hoge&quot; と &quot;object Hoge&quot; は 型の関係はなにもないはず </li></ul></ul></ul><ul><ul><ul><li>コンパイル後のクラスファイル名ってホントはちがう </li></ul></ul></ul><ul><ul><ul><ul><li>Hoge 、 Hoge$ のようなかんじ。。。 </li></ul></ul></ul></ul><ul><ul><li>設計上、暗黙の守るべきルールがあるのかではなかろうか? 教えてください </li></ul></ul>
  29. 29. object と apply メソッド <ul><li>今回作ったものの中では。。。 </li></ul><ul><li>                             コード再掲 </li></ul><ul><li>sealed trait Matrix </li></ul><ul><li>object Matrix { </li></ul><ul><li>def apply(x: Int, y: Int, z: Int): MatrixWithInt = MatrixWithInt(x, y, z) </li></ul><ul><li>def apply(x: Int, y: Int): MatrixWithInt2D = MatrixWithInt2D(x, y) </li></ul><ul><li>def apply(x: Double, y: Double, z: Double): MatrixWithDouble = MatrixWithDouble(x, y, z) </li></ul><ul><li>def apply(x: Double, y: Double): MatrixWithDouble2D = MatrixWithDouble2D(x, y) </li></ul><ul><li>} </li></ul><ul><li>ファクトリ役として使った </li></ul>
  30. 30. object と apply メソッド <ul><li>コンストラクタより、 apply メソッドのほうが、 柔軟にインスタンス生成できる </li></ul><ul><ul><li>生成する型を柔軟に切り替えられる </li></ul></ul><ul><ul><li>シングルトンを返却したり、こっそりインスタンスをキャッシュすることもできる </li></ul></ul><ul><ul><li>利用者のコードを変更せず、内部実装を切り替えられる </li></ul></ul><ul><ul><ul><li>こっそり、非パブリックなインスタンスを返却する用変更なんてことも可能 </li></ul></ul></ul><ul><ul><li>使用者が意図的に生成するインスタンスの型を決めたいなら、 apply メソッドで作らず、 &quot;createHoge&quot; みたいなメソッドのほうがいい </li></ul></ul><ul><ul><li>コンストラクタより劣ること </li></ul></ul><ul><ul><ul><li>めんどくさい </li></ul></ul></ul>
  31. 31. object と apply メソッド <ul><li>コンパニオンオブジェクト </li></ul><ul><ul><li>使命はなに? おしえてください </li></ul></ul><ul><ul><ul><li>class と同名の object をこうよぶのか? </li></ul></ul></ul><ul><ul><li>case class Foo() 、 object Foo val foo :Foo = Foo 後ろの Foo はオブジェクトなのかクラスなのかややこしい </li></ul></ul><ul><ul><ul><li>class と object が関係あるよとの意思表示として object Foo extends Foo とかしたほうがいいとかあるのかな。。 </li></ul></ul></ul>
  32. 32. おわり ありがとう ございました

×