More Related Content
Similar to 第一回社内 Scala 勉強会(一部抜粋) (20)
第一回社内 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