Rpscala2011 0601

1,188 views
1,170 views

Published on

scala勉強会 渋谷

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

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
1,188
On SlideShare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
1
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

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. おわり ありがとう ございました

×