Se está descargando tu SlideShare. ×

# How to get along with implicits

Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Anuncio
Próximo SlideShare
Clean code slide
Cargando en…3
×

1 de 51 Anuncio

# How to get along with implicits

ScalaMatsuri 2018

ScalaMatsuri 2018

Anuncio
Anuncio

Anuncio

Anuncio

### How to get along with implicits

1. 1. HOW TO GET ALONG WITH IMPLICIT Taisuke Oe / @OE_uia
2. 2. WHO AM I? Taisuke Oe @OE_uia A gleaner as: - the chairperson in ScalaMatsuri - VPoE in F-CODE, INC. Sometimes, a glean instructor as: - a technical advisor in Septeni Original, Inc. いろんな組織で落ち穂拾いしてます
3. 3. RECAP: WHAT IS IMPLICIT?
4. 4. TWO TYPES OF IMPLICIT Implicit parameter Implicit conversion
5. 5. SIMPLE IMPLICIT PARAMETER EXAMPLE from Scala Standard Library: trait Seq[A]{ def sorted[B >: A](implicit ord: math.Ordering[B]): Seq[A] } scala> Seq(2,1,3).sorted //Seq(1,2,3) ord: math.Ordering[B] argument is passed implicitly. Seq#sorted は最も単純な暗黙の引数の例
6. 6. SIMPLE IMPLICIT CONVERSION EXAMPLE from Scala Standard Library: import scala.collection.JavaConverters._ val jList:java.util.List[Int] = List(1,2,3).asJava
7. 7. IMPLICIT Why is Implicit regarded as dif cult? なぜ暗黙は難しいと思われがちなんだろう？
8. 8. WHY? - `Implicit` is NOT really explicit about what happens. You'll need some tools to gure it out. - `Implicit` scope is a bit complicated. Scaladoc cannot explain `Implicit` values in its scope. - `Implicit` is often designed to be induced. 暗黙の難しさ。 1) 何が起きているか明示されない 2) スコープがちょっと複雑 3)しばしば導出を前提にデザインされる
9. 9. AGAIN, SIMPLE IMPLICIT PARAMETER EXAMPLE Seq(2,1,3).sorted //Seq(1,2,3) Check with "-Xprint:typer" scalac option. 先程の例に戻り、どのように暗黙の値が解決されているか調べてみましょう。
10. 10. -XPRINT:TYPER DEMO
11. 11. -XPRINT:TYPER Sample.scala object Main{ Seq(2,1,3).sorted }
12. 12. \$ scalac -Xprint:typer Sample.scala [[syntax trees at end of typer]] // Sample.scala package <empty> { object Main extends scala.AnyRef { def <init>(): Main.type = { Main.super.<init>(); () }; scala.collection.Seq.apply[Int](2, 1, 3).sorted[Int](math.this.Ordering } } `-Xprint:typer` allows us to gure out how implicit is resolved. どのように暗黙の値の解決されてるか、分かる。
13. 13. FOR MORE COMPLICATED PROJECTS - Import working examples to IntelliJ IDEA - Use `Implicit Parameter` function (Implicit Analyzer) 複雑なプロジェクトには、IntelliJ IDEAでSImplicit Parameterを調べようという機能がオススメ。
14. 14. IMPLICIT ANALYZER DEMO
15. 15. HOW ABOUT IMPLICIT CONVERSION CASE? - As long as it's implemented in *Enrich my library pattern*, easy stuff. - *Enrich my library pattern* - Convert to a wrapper class with a new method you want. - *Go to Declarations* in IntelliJ, or something similar in your editor. Enrich my libraryパターンなら簡単に定義場所に飛べる
16. 16. HOW ABOUT IMPLICIT CONVERSION CASE? - Non *Enrich my library pattern* implicit conversion is not recommended. - Ah, good luck. - You can use `Implicit Conversions` in IntelliJ, Enrich my libraryパターンじゃない暗黙の型変換は、そもそも非推奨
17. 17. TIPS 1 Find working examples and analyze them. 動いているコードを探すのが、暗黙解決を理解するのに手っ取り早いでしょう
18. 18. FIND WORKING EXAMPLES Source codes that can compile. - project codes by your team. - Getting Started - examples in OSS project repositories - test codes サンプルコードを見つける場所候補。
19. 19. WHERE DOES ORDERING[INT] INSTANCE COME FROM? package scala.math object Ordering { trait IntOrdering extends Ordering[Int] { def compare(x: Int, y: Int) = java.lang.Integer.compare(x, y) } implicit object Int extends IntOrdering } scala.math.Ordering.Int is in its Implicit scope. scala.math.Ordering.Intが暗黙のスコープ内に定義されているので、先程の例はコンパイルできるのです。
20. 20. TIPS 2 Get familiar with common ways to include implicit values in the scope. 暗黙の値をスコープに加える代表的な方法を理解しよう。
21. 21. IMPLICIT SCOPE? Explicit imports / de nition Comapnion modules of associated types.
22. 22. EXPLICIT IMPORTS / DEFINITION import scala.concurrent._ import ExecutionContext.Implicits.global Future(1+2) Import values de ned in a certain object. (Its name is sometimes obviouse like *Implicits*) 暗黙の値が定義されているobjectの値をimportしよう。Implicitsみたいな分かりやすい名前が推奨
23. 23. COMAPNION MODULES OF ASSOCIATED TYPES Quotes from Scala Language Speci cation 7.2 Implicit parameter The implicit scope of a type T consists of all companion modules of classes The parts of a type T are: if T is a compound type T1 with …… with Tn, the union of the parts of T1, if T is a parameterized type S[T1,…,Tn], the union of the parts of SS and if T is a singleton type p.type, the parts of the type of p; if T is a type projection S#U, the parts of S as well as T itself; if T is a type alias, the parts of its expansion; if T is an abstract type, the parts of its upper bound; if T denotes an implicit conversion to a type with a method with argument the parts of quantified (existential or universal) and annotated types are define in all other cases, just T itself. 暗黙のスコープは、Scala言語仕様にまとまっています。
24. 24. COMPANION OBJECTS OF ... WHAT? You don't need to　understand *an associated type* 100%. Let's get along with common / ordinal patterns, one by one. 「関連のある型」のパターンを一緒に見てみよう
25. 25. FREQUENTLY USED IMPLICIT SCOPES
26. 26. PARAMETERIZED TYPE trait A object A { implicit val ba:B[A] = new B[A]{} } trait B[T] object B { implicit val bc:B[C] = new B[C]{} } trait C implicitly[B[A]] implicitly[B[C]] B[A]は、B,A両方のコンパニオンオブジェクト
27. 27. SUPER TYPE trait A trait B extends A object A{ implicit val b:B = new B{} } implicitly[B] 型Bのスーパー型Aのコンパニオンオブジェクトもスコープ内
28. 28. PACKAGE OBJECT package O trait A package object P{ implicit val a:A = new A{} } package P{ object B {implicitly[A]} }
29. 29. FOR REFERENCE.
30. 30. TYPE A trait A object A{ implicit val a:A = new A{} } implicitly[A] 型A自身のコンパニオンオブジェクト
31. 31. COMPOUND TYPE trait A object A{ implicit val ac:A with C = new A with C{} } trait C implicitly[A with C] A and C. 合成型A with Cは、AとC両方のコンパニオンオブジェクト。
32. 32. TYPE ALIAS trait A object A{ implicit val a:A = new A{} } type D = A implicitly[D]
33. 33. ABSTRACT TYPE WITH UPPER BOUND trait A trait ASub extends A trait B {type D <: A} object A extends B{ type D = ASub implicit val a:ASub = new ASub{} } implicitly[A.D]
34. 34. IMPLICIT CONVERSION trait A object A { implicit def f(a:A):B = new B{} implicit def g(b:B):A = new A{} } trait B val a:A = new B{} //NG //val b:B = new A{} 暗黙の型変換の、引数の型A
35. 35. IMPLICIT CLASS trait A object A { implicit class B(a:A) } implicitly[A => A.B] val b:A.B = new A{}
36. 36. TYPE PROJECTION trait A { trait E } object A { private val a:A = new A{} implicit val e:a.E = new a.E{} } implicitly[A#E]
37. 37. SINGLETON TYPE object A { implicit val a:A.type = this } implicitly[A.type] Associated type of A.type is A.
38. 38. WHERE DID WE FIND ORDERING[INT]? package scala.math object Ordering { trait IntOrdering extends Ordering[Int] { def compare(x: Int, y: Int) = java.lang.Integer.compare(x, y) } implicit object Int extends IntOrdering } In companion object of `Ordering`. Orderingのコンパニオンオブジェクトに定義していました。
39. 39. DEFINE YOUR OWN DATA TYPE. case class User(name:String) scala> Seq(User("B"),User("A")).sorted //ERROR since `Ordering[User]` instance is NOT defined within Implicit scope. Seq[User] can't be sorted since there is no Ordering[User] instance. User型を定義しただけだと、Seq[User]をsortedすることはできません。
40. 40. DEFINE ORDERING[USER] INSTANCE. case class User(name:String) object User{ //Get an Ordering[User] from Ordering[User] implicit val ordering:Ordering[User] = Ordering.by(_.name) } scala> Seq(User("B"),User("A")).sorted // Seq(User(A), User(B)) Ordering[User]型を得ることで、Seq[User]をsortedすることができました。 De ne Ordering[User] instance in companion object of `User`. Ordering[User]型を得ることで、Seq[User]をsortedすることができました。
41. 41. HOW DID WE DEFINE ORDERING[USER] INSTANCE? implicit val ordering:Ordering[User] = Ordering.by(_.name) object Ordering{ def by[T, S](f: (T) ⇒ S)(implicit ord: Ordering[S]): Ordering[T] } trait Ordering[T]{ def on[U](f: (U) ⇒ T): Ordering[U] } Watch out: direction of argument functions Ordering型のインスタンスは、既存のOrdering型から作ることができる。
42. 42. WAYS TO GET FROM EXISTING IMPLICIT VALUES There are so many ways to do so: Remember map , contramap and imap .
43. 43. MAP AND CONTRAMAP trait SerializedFormat trait Reads[T]{ def read(arg:SerializedFormat):T def map[U](f:T => U):Reads[U] } trait Writes[T]{ def writes(t:T):SerializedFormat def contramap[U](f: U => T):Writes[U] } `T` is in : return value position -> `map` argument position -> `contramap` 型パラメータが戻り値のポジションの場合は`map`, 引数のポジションの場合は `contramap`
44. 44. EXAMPLE: ORDERING[T] package scala.math trait Ordering[T] { //abstract method def compare(x: T, y: T): Int /* ... */ } Since `T` is in argument position, `Ordering.by` and `Ordering#on` are the same as `contramap`. Orderingの場合も例外ではなく、Tが引数ポジションだから`contramap` 相当のメソッド。
45. 45. OTHER EXAMPLES OF MAP AND CONTRAMAP play-json: Reads[T], Writes[T] ScalikeJDBC: TypeBinder[T], ParameterBinderFactory[T]
46. 46. IMAP trait Semigroup[T]{ //Like a standard Semigroup. def append(x:T,y:T):T //Like an InvariantFunctor def imap[A](f: T => A)(g: A => T): Semigroup[A] } `T` is in both of return value and argument position -> `imap` もしTが引数と戻り値の両方のポジションに出てくるなら、それは `imap` の出番だ
47. 47. OTHER EXAMPLES OF IMAP ScalikeJDBC: Binders[T] as xmap
48. 48. DERIVING (TYPECLASS) INSTANCES FROM OTHERS play-json uses macro to derive instances. e.g. Json.reads[T], Json.writes[T] shapeless uses HList to derive instances. e.g. shapeless-contrib
49. 49. AUTOMATIC DERIVATION EXAMPLE case class Value(i:Int) import MonoidSyntax._ import Monoid.typeClass._ Value(10) |+| Value(12) //Value(22)
50. 50. TIPS 3 Know basic ways to modify existing implicit values. (Brand-new de nition would be second option.) できるだけ既存の値を加工しよう
51. 51. CONCLUSION - `Implicit` is NOT really explicit about what happens. => Find working examples, and analyze them. - `Implicit` scope is a bit complicated. => Get familiar with common ways to include implicit values in the scope. - `Implicit` is often designed to be induced. => Know basic ways to modify existing implicit values. 暗黙とうまく付き合うための第一歩として、紹介したようなポイントを抑えましょう