32
Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/ Scala の言語機能 ここからが本番です 全ての言語機能について語るのは無理 本が書けるよ(多分上下巻)! Scala で何ができるようになるか、を重点した つもりConfidential

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

Embed Size (px)

DESCRIPTION

社内勉強会の資料から一部抜粋 アップロード時点でまだ勉強は実施されていない :-(

Citation preview

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能

ここからが本番です

全ての言語機能について語るのは無理

本が書けるよ(多分上下巻)!

Scala で何ができるようになるか、を重点した

つもり…

Confidential

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Java の場合

Nominal Subtyping

あるクラスと派生クラスの関係に基づく制約

Confidential

public class Duck { … } public class UglyDuck extends Duck { … } public class DuckBreeder<T extends Duck> { … }

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Java の場合

Nominal Subtyping

あるクラスと派生クラスの関係に基づく制約

予め継承している必要がある

Confidential

public class Duck { … } public class UglyDuck extends Duck { … } public class DuckBreeder<T extends Duck> { … }

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Scala の場合

Nominal Subtyping

勿論 Scala にもある

Confidential

class Duck { … } class UglyDuck extends Duck { … } class DuckBreeder[T <: Duck] { … }

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Java の場合

Nominal Subtyping

あるクラスとその派生型のみを許容

予め継承している必要がある

問題点:機能を備えていても、継承していないとダメ

Confidential

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

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Scala の場合

Structural Subtyping

クラスの構造に基づく制約

必要な機能を備えてさえいれば、継承関係は必要ない

Confidential

type HasIsEmpty = { def isEmpty(): Boolean } def genericIsEmpty[T <: HasIsEmpty](t: T) = t.isEmpty() genericIsEmpty(“”) genericIsEmpty(new java.util.ArrayList())

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Scala の場合

Structural Subtyping

クラスの構造に基づく制約

必要な機能を備えてさえいれば、継承関係は必要ない

実は名前をつける必要も制約にする必要もない

Confidential

def genericIsEmpty(v: { def isEmpty(): Boolean }) = v.isEmpty() genericIsEmpty(“”) genericIsEmpty(new java.util.ArrayList())

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Scala の場合

Structural Subtyping

クラスの構造に基づく制約

必要な機能を備えてさえいれば、継承関係は必要ない

実装にはリフレクションが使われているので注意

通常のメソッド呼び出しに比べると遙かに遅い

メソッドキャッシュもあるし、そこまで気にしなくてもいいけれど…

分割コンパイルの実現のために仕方なくこうなっている

Confidential

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Java の場合

機能を備えていないが、定義することができる場合

問題点:制約がどうのこうの以前の問題だ…

Confidential

public static char genericHead<T extends ???>(T t) { return t.head(); } genericHead(“akari”);

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Java の場合

機能を備えていないが、定義することができる場合

問題点:制約がどうのこうの以前の問題だ…

解決:Adapter pattern(GoF) を利用する

Confidential

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); } }

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Java の場合

機能を備えていないが、定義することができる場合

問題点:制約がどうのこうの以前の問題だ…

解決:Adapter pattern(GoF) を利用する

問題点:一々 Adapter 通すのが面倒…

Confidential

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

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Scala の場合

機能を備えていないが、定義することができる場合

Implicit Conversions により機能を備えた型に変換

Implicit と修飾された引数を一つ取る関数により定義

Confidential

trait Headable { def head(): Char } class StringHeadable(str: String) extends Headable { def head() = str.charAt(0) } implicit def stringIsHeadable(str: String) = new StringHeadable(str)

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Scala の場合

機能を備えていないが、定義することができる場合

Implicit Conversions により機能を備えた型に変換

Implicit と修飾された引数を一つ取る関数により定義

View Bounds と呼ばれる型制約が利用可能

Confidential

// T から Headable へ暗黙に変換可能なことを要求 def genericHead[T <% Headable](t: T) = t.head()

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Scala の場合

機能を備えていないが、定義することができる場合

Implicit Conversions により機能を備えた型に変換

Implicit と修飾された引数を一つ取る関数により定義

View Bounds と呼ばれる型制約が利用可能

変換は暗黙に行われる

Java の問題点を解決

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

Confidential

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

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Pimp My Library (pattern)

Implicit Conversions による機能追加の名称

Scala 標準ライブラリでも普通に使われている

Scala の String は java.lang.String

でも何故か何もしなくても head メソッドが呼べてしまう

予めリッチな型への暗黙変換が定義されているため

他にも色々

RichXXX とか WrappedXXX とか XXXOps とか

Confidential

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Pimp My Library と他言語の機能の比較

Ruby の Open Classes

グローバルに影響してしまう

Scala なら import によりコントロール可能

メソッドが「本当に」追加される(善し悪しは兎も角)

動的型付きなので型制約に関しては特になし

C# の Exntension Methods

単なる Syntax Sugar に過ぎない

よって、拡張したクラスが満たすことのできる制約は増えない

Confidential

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Implicit Conversions の弱点

定義が面倒なことがある

2.10 で導入される Implicit Classes である程度解決

変換の度に中間オブジェクトが生成される

2.10 で導入される Value Classes で解決

C# の Extension Methods とほとんど同じ

暗黙に行われるため、コードが追いづらい

Eclipse, IntelliJ IDEA なら変換箇所はハイライトされる

頑張れ

Confidential

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

ちょっと戻る

Confidential

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Java の場合

機能を備えていないが、定義することができる場合

問題点:制約がどうのこうの以前の問題だ…

解決:Adapter pattern をちょっと変形して利用

何を扱う Adapter なのかを型パラメタを取ることで分かるように

Confidential

public interface Headable<T> { char head(T t); } public class StringHeadable implements Headable<String> { @Override public char head(String str) { return str.charAt(0); } }

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Java の場合

機能を備えていないが、定義することができる場合

問題点:制約がどうのこうの以前の問題だ…

解決:Adapter pattern をちょっと変形して利用

問題点:やっぱり面倒…

型情報から何とかして適切な Adapter を選択できないか?

Confidential

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

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Scala の場合

機能を備えていないが、定義することができる場合

Implicit Patameter により機能を備えた値を要求

値は「型に基づいて」自動的に探索される(詳細は後述)

Adapter Pattern をちょっと変形したのはこれのため

Java の問題点解決!

Confidential

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

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Scala の場合

機能を備えていないが、定義することができる場合

Implicit Patameter により機能を備えた値を要求

Context Bounds と呼ばれる型制約も利用可能

直接は使わないが、必要とするメソッドを呼ぶとき等に

Confidential

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

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Scala の場合

機能を備えていないが、定義することができる場合

Implicit Patameter により機能を備えた値を要求

implicit と修飾された val, var, def, object が対象

var はやめておきましょうね…

Confidential

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

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Scala の Implicit Parameters

引数の候補はどこから選ばれる?

メソッドの利用箇所から見える定義群と(自明)

要求されている型のコンパニオンオブジェクト内から

複数見つかった場合は?

最も定義場所の近い物が優先される

同じ名前空間で複数見つかった場合はエラー

Confidential

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

コンパニオンオブジェクトとは?

クラスと同名のオブジェクト

User オブジェクトはコンパニオンオブジェクト

ここではこれ以上は触れません

Confidential

class User(name: String, age: Int) object User { … }

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

_人人人人人人人人人人_

> 突然の Type Classes <

 ̄Y^Y^Y^Y^Y^Y^Y^Y ̄

Confidential

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Scala の Implicit Parameters

実は Type Classes を実現するための言語機能

これまでのコードは下の Haskell コードと完全に一致

完全に一致、分かりましたですね?

Confidential

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)

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Type Classes

Functor, Applicative, Monad …

じゃない!!

モナモナするためだけのものではない

Type Classes = 型に機能を外から与える仕組み

あれ…なんだかデジャブ?

Implicit Conversions と Implicit Parameters って似てる?

実は Implicit Conversions も似たような物

手前味噌ですが参考

より詳細な話は今回はしません

Confidential

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

標準ライブラリにおける Type Classes の実例

scala.reflect.ClassManifest

ClassManifest[T] は T の型情報を扱う

配列の生成時によく使われる

scala.collection.generic.CanBuildFrom

CanBuildFrom[From, Elem, To] 三つも型パラメタが!

From というコレクションから

Elem を要素とする

To というコレクションを生成する

ための Builder[Elem, To] を提供する

Confidential

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

Implicit Parameters のその他の用法

Type Classes と全く関係ない利用法も

Fighting type erasure(pdf 注意、スライドです)

何らかのコンテキストを引き回す

android.os.Context の引き回し

弊社のアンドロイドアプリのコードでも使われている

play.api.Application の引き回し

弊社の API サーバーのコードでも使われている

play.api.db.Connection の引き回し

弊社の API サーバーのコードでも使われて…なかった

Confidential

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

まとめ 1

Structural Subtyping

継承関係ではなく構造に基づいた制約が可能

Implicit Conversions(View Bounds)

暗黙に変換可能かどうかに基づいた制約が可能

実は Implicit Parameters と大差ない

Implicit Parameters(Context Bounds)

暗黙に定義されているかどうかに基づいた制約が可能

実は Type Classes が実現可能

Confidential

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

Copyright © 2004-2012 Lepidum Co. Ltd. All rights reserved. https://lepidum.co.jp/

Scala の言語機能 – 型に対する制約

まとめ 2

Scala では様々な種類の型に対する制約がある

制約の種類が多い=柔軟に抽象的な設計が可能

アブストラクションヤッター!

触れなかったこと

Variance

Type constructor parameters

Lower bounds

これはまあ Java にもあるしね…

forSome

Confidential