SlideShare une entreprise Scribd logo
1  sur  32
Télécharger pour lire hors ligne
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

Contenu connexe

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

Beginners Scala in FAN 20121009
Beginners Scala in FAN 20121009Beginners Scala in FAN 20121009
Beginners Scala in FAN 20121009Taisuke Shiratori
 
Scala Daysに行ってみて
Scala Daysに行ってみてScala Daysに行ってみて
Scala Daysに行ってみてKota Mizushima
 
20110820 metaprogramming
20110820 metaprogramming20110820 metaprogramming
20110820 metaprogrammingMasanori Kado
 
Scalaのimplicit、カリー化
Scalaのimplicit、カリー化Scalaのimplicit、カリー化
Scalaのimplicit、カリー化yuya-nakamura
 
言語アップデート -Scala編-
言語アップデート -Scala編-言語アップデート -Scala編-
言語アップデート -Scala編-Kota Mizushima
 
Scalaでのプログラム開発
Scalaでのプログラム開発Scalaでのプログラム開発
Scalaでのプログラム開発Kota Mizushima
 
Scala再入門 @2014/02/08 Scala関西ビギナーズ第3回
Scala再入門 @2014/02/08 Scala関西ビギナーズ第3回Scala再入門 @2014/02/08 Scala関西ビギナーズ第3回
Scala再入門 @2014/02/08 Scala関西ビギナーズ第3回Asami Abe
 
【DL輪読会】Hierarchical Text-Conditional Image Generation with CLIP Latents
【DL輪読会】Hierarchical Text-Conditional Image Generation with CLIP Latents【DL輪読会】Hierarchical Text-Conditional Image Generation with CLIP Latents
【DL輪読会】Hierarchical Text-Conditional Image Generation with CLIP LatentsDeep Learning JP
 
Clojureで作る"simple"なDSL
Clojureで作る"simple"なDSLClojureで作る"simple"なDSL
Clojureで作る"simple"なDSLKent Ohashi
 
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...NTT DATA Technology & Innovation
 
Scalaで型クラス入門
Scalaで型クラス入門Scalaで型クラス入門
Scalaで型クラス入門Makoto Fukuhara
 
Scala2.8への移行
Scala2.8への移行Scala2.8への移行
Scala2.8への移行guest5f4320
 
Object-Functional Analysis and Design : 次世代モデリングパラダイムへの道標
Object-Functional Analysis and Design : 次世代モデリングパラダイムへの道標Object-Functional Analysis and Design : 次世代モデリングパラダイムへの道標
Object-Functional Analysis and Design : 次世代モデリングパラダイムへの道標Tomoharu ASAMI
 
Scalaによるドメイン特化言語を使ったソフトウェアの動作解析
Scalaによるドメイン特化言語を使ったソフトウェアの動作解析Scalaによるドメイン特化言語を使ったソフトウェアの動作解析
Scalaによるドメイン特化言語を使ったソフトウェアの動作解析Yamagata Yoriyuki
 
[豆ナイト]Java small object programming
[豆ナイト]Java small object programming[豆ナイト]Java small object programming
[豆ナイト]Java small object programmingYuichi Hasegawa
 

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

Beginners Scala in FAN 20121009
Beginners Scala in FAN 20121009Beginners Scala in FAN 20121009
Beginners Scala in FAN 20121009
 
Scalaノススメ
ScalaノススメScalaノススメ
Scalaノススメ
 
Scala Daysに行ってみて
Scala Daysに行ってみてScala Daysに行ってみて
Scala Daysに行ってみて
 
Java8勉強会
Java8勉強会Java8勉強会
Java8勉強会
 
キメるClojure
キメるClojureキメるClojure
キメるClojure
 
20110820 metaprogramming
20110820 metaprogramming20110820 metaprogramming
20110820 metaprogramming
 
Scalaのimplicit、カリー化
Scalaのimplicit、カリー化Scalaのimplicit、カリー化
Scalaのimplicit、カリー化
 
言語アップデート -Scala編-
言語アップデート -Scala編-言語アップデート -Scala編-
言語アップデート -Scala編-
 
Scalaでのプログラム開発
Scalaでのプログラム開発Scalaでのプログラム開発
Scalaでのプログラム開発
 
Datomic&datalog紹介
Datomic&datalog紹介Datomic&datalog紹介
Datomic&datalog紹介
 
Scala再入門 @2014/02/08 Scala関西ビギナーズ第3回
Scala再入門 @2014/02/08 Scala関西ビギナーズ第3回Scala再入門 @2014/02/08 Scala関西ビギナーズ第3回
Scala再入門 @2014/02/08 Scala関西ビギナーズ第3回
 
【DL輪読会】Hierarchical Text-Conditional Image Generation with CLIP Latents
【DL輪読会】Hierarchical Text-Conditional Image Generation with CLIP Latents【DL輪読会】Hierarchical Text-Conditional Image Generation with CLIP Latents
【DL輪読会】Hierarchical Text-Conditional Image Generation with CLIP Latents
 
Clojureで作る"simple"なDSL
Clojureで作る"simple"なDSLClojureで作る"simple"なDSL
Clojureで作る"simple"なDSL
 
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...
9/14にリリースされたばかりの新LTS版Java 17、ここ3年間のJavaの変化を知ろう!(Open Source Conference 2021 O...
 
Scalaで型クラス入門
Scalaで型クラス入門Scalaで型クラス入門
Scalaで型クラス入門
 
Scala2.8への移行
Scala2.8への移行Scala2.8への移行
Scala2.8への移行
 
Scala2.8への移行
Scala2.8への移行Scala2.8への移行
Scala2.8への移行
 
Object-Functional Analysis and Design : 次世代モデリングパラダイムへの道標
Object-Functional Analysis and Design : 次世代モデリングパラダイムへの道標Object-Functional Analysis and Design : 次世代モデリングパラダイムへの道標
Object-Functional Analysis and Design : 次世代モデリングパラダイムへの道標
 
Scalaによるドメイン特化言語を使ったソフトウェアの動作解析
Scalaによるドメイン特化言語を使ったソフトウェアの動作解析Scalaによるドメイン特化言語を使ったソフトウェアの動作解析
Scalaによるドメイン特化言語を使ったソフトウェアの動作解析
 
[豆ナイト]Java small object programming
[豆ナイト]Java small object programming[豆ナイト]Java small object programming
[豆ナイト]Java small object programming
 

第一回社内 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