SlideShare a Scribd company logo
Scala の言語機能
           ここからが本番です
                    全ての言語機能について語るのは無理
                            本が書けるよ(多分上下巻)!
                    Scala で何ができるようになるか、を重点した
                            つもり…




https://lepidum.co.jp/              Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Java の場合
                    Nominal Subtyping
                            あるクラスと派生クラスの関係に基づく制約
           public class Duck { … }
           public class UglyDuck extends Duck { … }
           public class DuckBreeder<T extends Duck> { … }




https://lepidum.co.jp/             Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Java の場合
                    Nominal Subtyping
                            あるクラスと派生クラスの関係に基づく制約
                            予め継承している必要がある
           public class Duck { … }
           public class UglyDuck extends Duck { … }
           public class DuckBreeder<T extends Duck> { … }




https://lepidum.co.jp/             Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Scala の場合
                    Nominal Subtyping
                            勿論 Scala にもある
           class Duck { … }
           class UglyDuck extends Duck { … }
           class DuckBreeder[T <: Duck] { … }




https://lepidum.co.jp/               Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Java の場合
                    Nominal Subtyping
                            あるクラスとその派生型のみを許容
                            予め継承している必要がある
                                問題点:機能を備えていても、継承していないとダメ

           public static boolean genericIsEmpty<T extends ???>(T t) {
             return t.isEmpty();
           }
           // String も List も isEmpty を持ってはいるが…
           genericIsEmpty(“”);
           genericIsEmpty(new ArrayList());


https://lepidum.co.jp/                Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Scala の場合
                    Structural Subtyping
                            クラスの構造に基づく制約
                            必要な機能を備えてさえいれば、継承関係は必要ない
           type HasIsEmpty = { def isEmpty(): Boolean }
           def genericIsEmpty[T <: HasIsEmpty](t: T) = t.isEmpty()
           genericIsEmpty(“”)
           genericIsEmpty(new java.util.ArrayList())




https://lepidum.co.jp/            Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Scala の場合
                    Structural Subtyping
                            クラスの構造に基づく制約
                            必要な機能を備えてさえいれば、継承関係は必要ない
                                実は名前をつける必要も制約にする必要もない
           def genericIsEmpty(v: { def isEmpty(): Boolean }) = v.isEmpty()
           genericIsEmpty(“”)
           genericIsEmpty(new java.util.ArrayList())




https://lepidum.co.jp/                Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Scala の場合
                    Structural Subtyping
                            クラスの構造に基づく制約
                            必要な機能を備えてさえいれば、継承関係は必要ない
                            実装にはリフレクションが使われているので注意
                                通常のメソッド呼び出しに比べると遙かに遅い
                                メソッドキャッシュもあるし、そこまで気にしなくてもいいけれど…
                                分割コンパイルの実現のために仕方なくこうなっている




https://lepidum.co.jp/                Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Java の場合
                    機能を備えていないが、定義することができる場合
                            問題点:制約がどうのこうの以前の問題だ…
           public static char genericHead<T extends ???>(T t) {
             return t.head();
           }
           genericHead(“akari”);




https://lepidum.co.jp/             Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Java の場合
                    機能を備えていないが、定義することができる場合
                            問題点:制約がどうのこうの以前の問題だ…
                            解決:Adapter pattern(GoF) を利用する
           public interface Headable { char head(); }
           public class StringHeadableAdapter implements Headable {
             private String str;
             public StringHeadable(String str) { this.str = str; }
             @Override
             public char head() { return str.charAt(0); }
           }



https://lepidum.co.jp/               Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Java の場合
                    機能を備えていないが、定義することができる場合
                            問題点:制約がどうのこうの以前の問題だ…
                            解決:Adapter pattern(GoF) を利用する
                                 問題点:一々 Adapter 通すのが面倒…
           public static char genericHead<T extends Headable>(T t) {
             return t.head();
           }
           genericHead(new StringHeadableAdapter(“akari”));




https://lepidum.co.jp/                  Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Scala の場合
                    機能を備えていないが、定義することができる場合
                            Implicit Conversions により機能を備えた型に変換
                                 Implicit と修飾された引数を一つ取る関数により定義
           trait Headable { def head(): Char }
           class StringHeadable(str: String) extends Headable {
             def head() = str.charAt(0)
           }
           implicit def stringIsHeadable(str: String) =
             new StringHeadable(str)




https://lepidum.co.jp/                  Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Scala の場合
                    機能を備えていないが、定義することができる場合
                            Implicit Conversions により機能を備えた型に変換
                                 Implicit と修飾された引数を一つ取る関数により定義
                                 View Bounds と呼ばれる型制約が利用可能
           // T から Headable へ暗黙に変換可能なことを要求
           def genericHead[T <% Headable](t: T) = t.head()




https://lepidum.co.jp/                  Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Scala の場合
                    機能を備えていないが、定義することができる場合
                            Implicit Conversions により機能を備えた型に変換
                                 Implicit と修飾された引数を一つ取る関数により定義
                                 View Bounds と呼ばれる型制約が利用可能
                                 変換は暗黙に行われる
                                     Java の問題点を解決

                                         明示的に変換することもできる


           genericHead(“akari”)
           genericHead(stringIsHeadable(“akari”))
           genericHead(new StringHeadable(“akari”))


https://lepidum.co.jp/                  Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Pimp My Library (pattern)
                    Implicit Conversions による機能追加の名称
                    Scala 標準ライブラリでも普通に使われている
                            Scala の String は java.lang.String
                                 でも何故か何もしなくても head メソッドが呼べてしまう
                                    予めリッチな型への暗黙変換が定義されているため


                            他にも色々
                                 RichXXX とか WrappedXXX とか XXXOps とか




https://lepidum.co.jp/                    Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Pimp My Library と他言語の機能の比較
                    Ruby の Open Classes
                            グローバルに影響してしまう
                                 Scala なら import によりコントロール可能
                            メソッドが「本当に」追加される(善し悪しは兎も角)
                            動的型付きなので型制約に関しては特になし
                    C# の Exntension Methods
                            単なる Syntax Sugar に過ぎない
                                 よって、拡張したクラスが満たすことのできる制約は増えない


https://lepidum.co.jp/                   Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Implicit Conversions の弱点
                    定義が面倒なことがある
                            2.10 で導入される Implicit Classes である程度解決
                    変換の度に中間オブジェクトが生成される
                            2.10 で導入される Value Classes で解決
                                 C# の Extension Methods とほとんど同じ
                    暗黙に行われるため、コードが追いづらい
                            Eclipse, IntelliJ IDEA なら変換箇所はハイライトされる
                                 頑張れ


https://lepidum.co.jp/                    Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約




                                ちょっと戻る




https://lepidum.co.jp/   Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Java の場合
                    機能を備えていないが、定義することができる場合
                            問題点:制約がどうのこうの以前の問題だ…
                            解決:Adapter pattern をちょっと変形して利用
                                 何を扱う Adapter なのかを型パラメタを取ることで分かるように
           public interface Headable<T> { char head(T t); }
           public class StringHeadable implements Headable<String> {
             @Override
             public char head(String str) { return str.charAt(0); }
           }




https://lepidum.co.jp/                  Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Java の場合
                    機能を備えていないが、定義することができる場合
                            問題点:制約がどうのこうの以前の問題だ…
                            解決:Adapter pattern をちょっと変形して利用
                                 問題点:やっぱり面倒…
                                    型情報から何とかして適切な Adapter を選択できないか?

           public static char genericHead<T>(T t, Headable<T> ev) {
             return ev.head(t);
           }
           genericHead(“akari”, new StringHeadable());




https://lepidum.co.jp/                  Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Scala の場合
                    機能を備えていないが、定義することができる場合
                            Implicit Patameter により機能を備えた値を要求
                                 値は「型に基づいて」自動的に探索される(詳細は後述)
                                    Adapter Pattern をちょっと変形したのはこれのため

                                    Java の問題点解決!

           def genericHead[T](T t)(implicit ev: Headable[T]) = {
             ev.head(t)
           }
           genericHead(“akari”) // ev は適切な値が見つかれば自動的に渡される




https://lepidum.co.jp/                   Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Scala の場合
                    機能を備えていないが、定義することができる場合
                            Implicit Patameter により機能を備えた値を要求
                                 Context Bounds と呼ばれる型制約も利用可能
                                     直接は使わないが、必要とするメソッドを呼ぶとき等に


           // Headable[T] が暗黙に定義されていることを要求
           def genericHeadAsString[T : Headable](T t) = {
             genericHead(t).toString
           }




https://lepidum.co.jp/                 Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Scala の場合
                    機能を備えていないが、定義することができる場合
                            Implicit Patameter により機能を備えた値を要求
                                 implicit と修飾された val, var, def, object が対象
                                     var はやめておきましょうね…


           trait Headable[T] { def head(t: T): Char }
           implicit object stringHeadable extends Headable[String] {
             def head(str: String) = str.charAt(0)
           }




https://lepidum.co.jp/                     Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Scala の Implicit Parameters
                    引数の候補はどこから選ばれる?
                            メソッドの利用箇所から見える定義群と(自明)
                            要求されている型のコンパニオンオブジェクト内から
                    複数見つかった場合は?
                            最も定義場所の近い物が優先される
                            同じ名前空間で複数見つかった場合はエラー




https://lepidum.co.jp/             Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           コンパニオンオブジェクトとは?
                    クラスと同名のオブジェクト
                            User オブジェクトはコンパニオンオブジェクト
                                ここではこれ以上は触れません
           class User(name: String, age: Int)
           object User {
             …
           }




https://lepidum.co.jp/                Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約



                         _人人人人人人人人人人_
                         > 突然の Type Classes <
                          ̄Y^Y^Y^Y^Y^Y^Y^Y ̄




https://lepidum.co.jp/       Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Scala の Implicit Parameters
                    実は Type Classes を実現するための言語機能
                            これまでのコードは下の Haskell コードと完全に一致
                                完全に一致、分かりましたですね?
           class Headable a where
             head :: a -> Char

           instance Headable String where
             head str = str !! 0

           headAsString :: Headable a => a -> String
           headAsString a = show (head a)




https://lepidum.co.jp/                Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Type Classes
                    Functor, Applicative, Monad …
                            じゃない!!
                                モナモナするためだけのものではない
                    Type Classes = 型に機能を外から与える仕組み
                            あれ…なんだかデジャブ?
                                Implicit Conversions と Implicit Parameters って似てる?
                                    実は Implicit Conversions も似たような物

                                        手前味噌ですが参考


                    より詳細な話は今回はしません
https://lepidum.co.jp/                    Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           標準ライブラリにおける Type Classes の実例
                    scala.reflect.ClassManifest
                            ClassManifest[T] は T の型情報を扱う
                                 配列の生成時によく使われる
                    scala.collection.generic.CanBuildFrom
                            CanBuildFrom[From, Elem, To] 三つも型パラメタが!
                                 From というコレクションから
                                 Elem を要素とする
                                 To というコレクションを生成する
                                     ための Builder[Elem, To] を提供する




https://lepidum.co.jp/                    Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           Implicit Parameters のその他の用法
                    Type Classes と全く関係ない利用法も
                            Fighting type erasure(pdf 注意、スライドです)
                            何らかのコンテキストを引き回す
                                 android.os.Context の引き回し
                                     弊社のアンドロイドアプリのコードでも使われている

                                 play.api.Application の引き回し
                                     弊社の API サーバーのコードでも使われている

                                 play.api.db.Connection の引き回し
                                     弊社の API サーバーのコードでも使われて…なかった




https://lepidum.co.jp/                  Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           まとめ 1
                    Structural Subtyping
                            継承関係ではなく構造に基づいた制約が可能
                    Implicit Conversions(View Bounds)
                            暗黙に変換可能かどうかに基づいた制約が可能
                                実は Implicit Parameters と大差ない
                    Implicit Parameters(Context Bounds)
                            暗黙に定義されているかどうかに基づいた制約が可能
                                実は Type Classes が実現可能


https://lepidum.co.jp/                   Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential
Scala の言語機能 – 型に対する制約
           まとめ 2
                    Scala では様々な種類の型に対する制約がある
                            制約の種類が多い=柔軟に抽象的な設計が可能
                                 アブストラクションヤッター!
                    触れなかったこと
                            Variance
                            Type constructor parameters
                            Lower bounds
                                 これはまあ Java にもあるしね…
                            forSome
https://lepidum.co.jp/                  Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved.   Confidential

More Related Content

第一回社内 Scala 勉強会(一部抜粋)

  • 1. Scala の言語機能  ここからが本番です  全ての言語機能について語るのは無理  本が書けるよ(多分上下巻)!  Scala で何ができるようになるか、を重点した  つもり… https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 2. Scala の言語機能 – 型に対する制約  Java の場合  Nominal Subtyping  あるクラスと派生クラスの関係に基づく制約 public class Duck { … } public class UglyDuck extends Duck { … } public class DuckBreeder<T extends Duck> { … } https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 3. Scala の言語機能 – 型に対する制約  Java の場合  Nominal Subtyping  あるクラスと派生クラスの関係に基づく制約  予め継承している必要がある public class Duck { … } public class UglyDuck extends Duck { … } public class DuckBreeder<T extends Duck> { … } https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 4. Scala の言語機能 – 型に対する制約  Scala の場合  Nominal Subtyping  勿論 Scala にもある class Duck { … } class UglyDuck extends Duck { … } class DuckBreeder[T <: Duck] { … } https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 5. Scala の言語機能 – 型に対する制約  Java の場合  Nominal Subtyping  あるクラスとその派生型のみを許容  予め継承している必要がある  問題点:機能を備えていても、継承していないとダメ public static boolean genericIsEmpty<T extends ???>(T t) { return t.isEmpty(); } // String も List も isEmpty を持ってはいるが… genericIsEmpty(“”); genericIsEmpty(new ArrayList()); https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 6. Scala の言語機能 – 型に対する制約  Scala の場合  Structural Subtyping  クラスの構造に基づく制約  必要な機能を備えてさえいれば、継承関係は必要ない type HasIsEmpty = { def isEmpty(): Boolean } def genericIsEmpty[T <: HasIsEmpty](t: T) = t.isEmpty() genericIsEmpty(“”) genericIsEmpty(new java.util.ArrayList()) https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 7. Scala の言語機能 – 型に対する制約  Scala の場合  Structural Subtyping  クラスの構造に基づく制約  必要な機能を備えてさえいれば、継承関係は必要ない  実は名前をつける必要も制約にする必要もない def genericIsEmpty(v: { def isEmpty(): Boolean }) = v.isEmpty() genericIsEmpty(“”) genericIsEmpty(new java.util.ArrayList()) https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 8. Scala の言語機能 – 型に対する制約  Scala の場合  Structural Subtyping  クラスの構造に基づく制約  必要な機能を備えてさえいれば、継承関係は必要ない  実装にはリフレクションが使われているので注意  通常のメソッド呼び出しに比べると遙かに遅い  メソッドキャッシュもあるし、そこまで気にしなくてもいいけれど…  分割コンパイルの実現のために仕方なくこうなっている https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 9. Scala の言語機能 – 型に対する制約  Java の場合  機能を備えていないが、定義することができる場合  問題点:制約がどうのこうの以前の問題だ… public static char genericHead<T extends ???>(T t) { return t.head(); } genericHead(“akari”); https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 10. Scala の言語機能 – 型に対する制約  Java の場合  機能を備えていないが、定義することができる場合  問題点:制約がどうのこうの以前の問題だ…  解決:Adapter pattern(GoF) を利用する public interface Headable { char head(); } public class StringHeadableAdapter implements Headable { private String str; public StringHeadable(String str) { this.str = str; } @Override public char head() { return str.charAt(0); } } https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 11. Scala の言語機能 – 型に対する制約  Java の場合  機能を備えていないが、定義することができる場合  問題点:制約がどうのこうの以前の問題だ…  解決:Adapter pattern(GoF) を利用する  問題点:一々 Adapter 通すのが面倒… public static char genericHead<T extends Headable>(T t) { return t.head(); } genericHead(new StringHeadableAdapter(“akari”)); https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 12. Scala の言語機能 – 型に対する制約  Scala の場合  機能を備えていないが、定義することができる場合  Implicit Conversions により機能を備えた型に変換  Implicit と修飾された引数を一つ取る関数により定義 trait Headable { def head(): Char } class StringHeadable(str: String) extends Headable { def head() = str.charAt(0) } implicit def stringIsHeadable(str: String) = new StringHeadable(str) https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 13. Scala の言語機能 – 型に対する制約  Scala の場合  機能を備えていないが、定義することができる場合  Implicit Conversions により機能を備えた型に変換  Implicit と修飾された引数を一つ取る関数により定義  View Bounds と呼ばれる型制約が利用可能 // T から Headable へ暗黙に変換可能なことを要求 def genericHead[T <% Headable](t: T) = t.head() https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 14. Scala の言語機能 – 型に対する制約  Scala の場合  機能を備えていないが、定義することができる場合  Implicit Conversions により機能を備えた型に変換  Implicit と修飾された引数を一つ取る関数により定義  View Bounds と呼ばれる型制約が利用可能  変換は暗黙に行われる  Java の問題点を解決  明示的に変換することもできる genericHead(“akari”) genericHead(stringIsHeadable(“akari”)) genericHead(new StringHeadable(“akari”)) https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 15. Scala の言語機能 – 型に対する制約  Pimp My Library (pattern)  Implicit Conversions による機能追加の名称  Scala 標準ライブラリでも普通に使われている  Scala の String は java.lang.String  でも何故か何もしなくても head メソッドが呼べてしまう  予めリッチな型への暗黙変換が定義されているため  他にも色々  RichXXX とか WrappedXXX とか XXXOps とか https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 16. Scala の言語機能 – 型に対する制約  Pimp My Library と他言語の機能の比較  Ruby の Open Classes  グローバルに影響してしまう  Scala なら import によりコントロール可能  メソッドが「本当に」追加される(善し悪しは兎も角)  動的型付きなので型制約に関しては特になし  C# の Exntension Methods  単なる Syntax Sugar に過ぎない  よって、拡張したクラスが満たすことのできる制約は増えない https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 17. Scala の言語機能 – 型に対する制約  Implicit Conversions の弱点  定義が面倒なことがある  2.10 で導入される Implicit Classes である程度解決  変換の度に中間オブジェクトが生成される  2.10 で導入される Value Classes で解決  C# の Extension Methods とほとんど同じ  暗黙に行われるため、コードが追いづらい  Eclipse, IntelliJ IDEA なら変換箇所はハイライトされる  頑張れ https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 18. Scala の言語機能 – 型に対する制約 ちょっと戻る https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 19. Scala の言語機能 – 型に対する制約  Java の場合  機能を備えていないが、定義することができる場合  問題点:制約がどうのこうの以前の問題だ…  解決:Adapter pattern をちょっと変形して利用  何を扱う Adapter なのかを型パラメタを取ることで分かるように public interface Headable<T> { char head(T t); } public class StringHeadable implements Headable<String> { @Override public char head(String str) { return str.charAt(0); } } https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 20. Scala の言語機能 – 型に対する制約  Java の場合  機能を備えていないが、定義することができる場合  問題点:制約がどうのこうの以前の問題だ…  解決:Adapter pattern をちょっと変形して利用  問題点:やっぱり面倒…  型情報から何とかして適切な Adapter を選択できないか? public static char genericHead<T>(T t, Headable<T> ev) { return ev.head(t); } genericHead(“akari”, new StringHeadable()); https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 21. Scala の言語機能 – 型に対する制約  Scala の場合  機能を備えていないが、定義することができる場合  Implicit Patameter により機能を備えた値を要求  値は「型に基づいて」自動的に探索される(詳細は後述)  Adapter Pattern をちょっと変形したのはこれのため  Java の問題点解決! def genericHead[T](T t)(implicit ev: Headable[T]) = { ev.head(t) } genericHead(“akari”) // ev は適切な値が見つかれば自動的に渡される https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 22. Scala の言語機能 – 型に対する制約  Scala の場合  機能を備えていないが、定義することができる場合  Implicit Patameter により機能を備えた値を要求  Context Bounds と呼ばれる型制約も利用可能  直接は使わないが、必要とするメソッドを呼ぶとき等に // Headable[T] が暗黙に定義されていることを要求 def genericHeadAsString[T : Headable](T t) = { genericHead(t).toString } https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 23. Scala の言語機能 – 型に対する制約  Scala の場合  機能を備えていないが、定義することができる場合  Implicit Patameter により機能を備えた値を要求  implicit と修飾された val, var, def, object が対象  var はやめておきましょうね… trait Headable[T] { def head(t: T): Char } implicit object stringHeadable extends Headable[String] { def head(str: String) = str.charAt(0) } https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 24. Scala の言語機能 – 型に対する制約  Scala の Implicit Parameters  引数の候補はどこから選ばれる?  メソッドの利用箇所から見える定義群と(自明)  要求されている型のコンパニオンオブジェクト内から  複数見つかった場合は?  最も定義場所の近い物が優先される  同じ名前空間で複数見つかった場合はエラー https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 25. Scala の言語機能 – 型に対する制約  コンパニオンオブジェクトとは?  クラスと同名のオブジェクト  User オブジェクトはコンパニオンオブジェクト  ここではこれ以上は触れません class User(name: String, age: Int) object User { … } https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 26. Scala の言語機能 – 型に対する制約 _人人人人人人人人人人_ > 突然の Type Classes <  ̄Y^Y^Y^Y^Y^Y^Y^Y ̄ https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 27. Scala の言語機能 – 型に対する制約  Scala の Implicit Parameters  実は Type Classes を実現するための言語機能  これまでのコードは下の Haskell コードと完全に一致  完全に一致、分かりましたですね? class Headable a where head :: a -> Char instance Headable String where head str = str !! 0 headAsString :: Headable a => a -> String headAsString a = show (head a) https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 28. Scala の言語機能 – 型に対する制約  Type Classes  Functor, Applicative, Monad …  じゃない!!  モナモナするためだけのものではない  Type Classes = 型に機能を外から与える仕組み  あれ…なんだかデジャブ?  Implicit Conversions と Implicit Parameters って似てる?  実は Implicit Conversions も似たような物  手前味噌ですが参考  より詳細な話は今回はしません https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 29. Scala の言語機能 – 型に対する制約  標準ライブラリにおける Type Classes の実例  scala.reflect.ClassManifest  ClassManifest[T] は T の型情報を扱う  配列の生成時によく使われる  scala.collection.generic.CanBuildFrom  CanBuildFrom[From, Elem, To] 三つも型パラメタが!  From というコレクションから  Elem を要素とする  To というコレクションを生成する  ための Builder[Elem, To] を提供する https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 30. Scala の言語機能 – 型に対する制約  Implicit Parameters のその他の用法  Type Classes と全く関係ない利用法も  Fighting type erasure(pdf 注意、スライドです)  何らかのコンテキストを引き回す  android.os.Context の引き回し  弊社のアンドロイドアプリのコードでも使われている  play.api.Application の引き回し  弊社の API サーバーのコードでも使われている  play.api.db.Connection の引き回し  弊社の API サーバーのコードでも使われて…なかった https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 31. Scala の言語機能 – 型に対する制約  まとめ 1  Structural Subtyping  継承関係ではなく構造に基づいた制約が可能  Implicit Conversions(View Bounds)  暗黙に変換可能かどうかに基づいた制約が可能  実は Implicit Parameters と大差ない  Implicit Parameters(Context Bounds)  暗黙に定義されているかどうかに基づいた制約が可能  実は Type Classes が実現可能 https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential
  • 32. Scala の言語機能 – 型に対する制約  まとめ 2  Scala では様々な種類の型に対する制約がある  制約の種類が多い=柔軟に抽象的な設計が可能  アブストラクションヤッター!  触れなかったこと  Variance  Type constructor parameters  Lower bounds  これはまあ Java にもあるしね…  forSome https://lepidum.co.jp/ Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. Confidential