2018-10-15-kotlin13

Daec7e5cd5fae384eda88037d937343b?s=47 AAkira
October 15, 2018

 2018-10-15-kotlin13

Kotlin Conf2018 報告会
Kotlin1.3新機能
@CA.kt

Daec7e5cd5fae384eda88037d937343b?s=128

AAkira

October 15, 2018
Tweet

Transcript

  1. AAkira @_a_akira Kotlin Conf2018報告会 - Kotlin 1.3新機能-

  2. About me @_a_akira AAkira CyberAgent, Inc. Akira Aratani https://aakira.app !"#$%&'()*+,-./012345

  3. None
  4. New Type Inference and Related Language Features Svetlana Isakova Svetlana

    Isakova has worked on the Kotlin language at JetBrains. She’s co-authored the book Kotlin in Action and now is a Developer Advocate, where she spends her time teaching Kotlin and speaking at conferences worldwide.
  5. Agenda • Experimental features • Contracts • New type Inference

  6. λΠτϧ Experimental features

  7. Experimental features Purpose To let new features be tried by

    early adopters 
 as soon as possible
  8. Experimental features Tools > Kotlin > Enable migrations detection (experimental)

  9. Experimental features Migration tool

  10. Experimental features experimentalの機能を使う場合はgradleに追加するする必要がある kotlin { 
 experimental { coroutines 'enable'

    } }
  11. Experimental features import kotlinx.coroutines.experimental.* import kotlinx.coroutines.* ˣ 1.2 1.3

  12. Experimental features 自分でExperimental APIを作ることも可能 @Experimental annotation class ShinyNewAPI

  13. Experimental features // Ϋϥεʹ΋෇͚ΒΕΔ @ShinyNewAPI class Foo {} // ؔ਺ʹ΋෇͚ΒΕΔ

    @ShinyNewAPI fun Foo.bar() = ""
  14. Experimental features @ShinyNewAPI fun doSomething() { val foo = Foo()

    foo.bar() } @ShinyNewAPI fun main() { doSomething() }
  15. Experimental features @ShinyNewAPI fun doSomething() { val foo = Foo()

    foo.bar() } @ShinyNewAPI fun main() { doSomething() } 1.3からmain関数の引数はオプションになった
  16. Experimental features @ShinyNewAPI fun doSomething() { val foo = Foo()

    foo.bar() } @ShinyNewAPI fun main() { doSomething() }
  17. Experimental features @UseExperimental(ShinyNewAPI::class) fun doSomething() { val foo = Foo()

    foo.bar() } 
 fun main() { doSomething() }
  18. Experimental features @UseExperimental(ShinyNewAPI::class) fun doSomething() { val foo = Foo()

    foo.bar() } 
 fun main() { doSomething() }
  19. $POUSBDUT Contracts

  20. Kotlin Puzzler Kotlin1.2で実行する場合 fun main(args: Array<String>) { var hoge: Int?

    run { hoge = 46 } println(hoge) } // a) 46 // b) NullPointerException // c) null // d) Will not compile
  21. Kotlin Puzzler Kotlin 1.3より前では実行出来ない fun main(args: Array<String>) { var hoge:

    Int? run { hoge = 46 } println(hoge) } // a) 46 // b) NullPointerException // c) null // d) Will not compile
  22. Kotlin Puzzler fun main(args: Array<String>) { var hoge: Int? run

    { hoge = 46 } println(hoge) } // a) 46 // b) NullPointerException // c) null // d) Will not compile コンパイラは初期化されているのか、判断出来ない 
 printの部分で “variable hoge must be initialized”
  23. Contracts // 1.3 inline fun <R> run(block: () -> R):

    R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return block() } // 1.2
 public inline fun <R> run(block: () -> R): R = block()
  24. Contracts // 1.3 inline fun <R> run(block: () -> R):

    R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return block() } // 1.2
 public inline fun <R> run(block: () -> R): R = block()
  25. Contracts • can be implicitly changed • can implicitly break

    code depending on it なぜコンパイラはrun内で代入されたhogeがnon-nullなのを理解出来ないのか
  26. Contracts // 1.3 inline fun <R> run(block: () -> R):

    R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return block() } // 1.2
 public inline fun <R> run(block: () -> R): R = block() コンパイラに一度だけ実行されるという情報を
 教えてあげる
  27. Contracts Kotlin 1.3では実行可能 fun main(args: Array<String>) { var hoge: Int?

    run { hoge = 46 } println(hoge) }
  28. Contracts Kotlin 1.3より前では実行出来ない fun main(args: Array<String>) {
 val s :

    String? = "" if(!s.isNullOrEmpty()) { s.first() }
 }
  29. Contracts Kotlin 1.3より前では実行出来ない fun main(args: Array<String>) {
 val s :

    String? = "" if(!s.isNullOrEmpty()) { s.first() }
 } sがnot nullだとはコンパイラは理解出来ない
  30. Contracts 1.3でのisNullOrEmptyの実装 public inline fun CharSequence?.isNullOrEmpty(): Boolean { contract {

    returns(false) implies (this@isNullOrEmpty != null) } return this == null || this.length == 0 }
  31. Contracts 1.3でのisNullOrEmptyの実装 public inline fun CharSequence?.isNullOrEmpty(): Boolean { contract {

    returns(false) implies (this@isNullOrEmpty != null) } return this == null || this.length == 0 } return falseの時に
 isNullOrEmpty != nullの情報を
 コンパイラに教える
  32. Contracts Kotlin 1.3では実行可能 fun main(args: Array<String>) {
 val s :

    String? = "" if(!s.isNullOrEmpty()) { s.first() }
 }
  33. Contracts 自作も可能 @ExperimentalContracts private inline fun CharSequence?.hoge(): Boolean { contract

    { returns(false) implies (this@hoge != null) } return this == null || this.length == 0 }
 
 @ExperimentalContracts fun main() { var a: String? = "abc" if (!a.hoge()) { println(a.first()) } }
  34. 自作も可能 Contracts @ExperimentalContracts private inline fun CharSequence?.hoge(): Boolean { contract

    { returns(false) implies (this@hoge != null) } return this == null || this.length == 0 }
 
 @ExperimentalContracts fun main() { var a: String? = "abc" if (!a.hoge()) { println(a.first()) } } contractもExperimentalContracts annotationが必要
  35. Contracts @UseExperimental(ExperimentalContracts::class) private inline fun CharSequence?.hoge(): Boolean { contract {

    returns(false) implies (this@hoge != null) } return this == null || this.length == 0 } fun main() { var a: String? = "abc" if (!a.hoge()) { println(a.first()) } } UseExperimentalで書き換え可能
  36. Contracts @UseExperimental(ExperimentalContracts::class) private inline fun CharSequence?.hoge(): Boolean { contract {

    returns(false) implies (this@hoge != null) } return this == null || this.length == 0 } fun main() { var a: String? = "abc" if (!a.hoge()) { println(a.first()) } } ここでも、UseExperimental annotationが使える UseExperimentalで書き換え可能
  37. Contracts @UseExperimental(ExperimentalContracts::class) private inline fun CharSequence?.hoge(): Boolean { contract {

    returns(false) implies (this@hoge != null) } return this == null || this.length == 0 } fun main() { var a: String? = "abc" if (!a.hoge()) { println(a.first()) } } annotationが不要
  38. Contracts • run, let, with, apply, also, takeIf, takeUnless, synchronized

    • isNullOrEmpty, isNullOrBlank, • kotlin.test: assertTrue, assertFalse, assertNotNull • check, checkNotNull, require, requireNotNull Contractが追加されたメソッド達
  39. /FXUZQFJOGFSFODF New type inference

  40. New type inference kotlin { 
 experimental { newInference 'enable'

    } }
  41. New type inference • SAM conversions for Kotlin functions •

    Better inference for builders • Better inference for call chains • Better inference for intersection types
  42. public interface Action<T> { void execute(T target); } SAM conversions

    .java fun handleInput(handler: Action<String>) { ... } fun main() { handleInput(Action { target -> println(target) 
 }) } .kt
  43. public interface Action<T> { void execute(T target); } SAM conversions

    .java fun handleInput(handler: Action<String>) { ... } fun main() {
 handleInput { println(it) } } .kt 1.3からはこう書ける
  44. SAM conversions val obs = Observable.just(100) Observable.just(1) .zipWith<Int, Int>(obs, BiFunction

    { a, b -> a + b }) .subscribe { } RxJava2から第二引数でlamda式が使えなくなっていた
 => RxKotlin(https://github.com/ReactiveX/RxKotlin) で回避していた
  45. SAM conversions val obs = Observable.just(100) Observable.just(1) .zipWith(obs) { a,

    b -> a + b } .subscribe { } RxKotlinを使わなくても良くなった!
  46. Inference for builder lambdas val seq = sequence { yield(42)

    print("hoge") yield(4) } Kotlin1.3から型パラメータが不要
  47. Inference for builder lambdas Kotlin1.3から型パラメータが不要 val seq = sequence<Int> {

    yield(42) print("hoge") yield(4) }
  48. Inference for builder lambdas fun <T> buildList( init: MutableList<T>.() ->

    Unit ): List<T> { return mutableListOf<T>().apply(init) } fun main() { val list = buildList<Int> { add(1) add(2) } } もちろん自分でも定義可能
  49. Inference for builder lambdas @UseExperimental(ExperimentalTypeInference::class) fun <T> buildList( @BuilderInference init:

    MutableList<T>.() -> Unit ): List<T> { return mutableListOf<T>().apply(init) } fun main() { val list = buildList<Int> { add(1) add(2) } } BuilderInference annotationを使う
  50. Inference for builder lambdas @UseExperimental(ExperimentalTypeInference::class) fun <T> buildList( @BuilderInference init:

    MutableList<T>.() -> Unit ): List<T> { return mutableListOf<T>().apply(init) } fun main() { val list = buildList<Int> { add(1) add(2) } } BuilderInference annotationを使う
  51. Inference for builder lambdas @UseExperimental(ExperimentalTypeInference::class) fun <T> buildList( @BuilderInference init:

    MutableList<T>.() -> Unit ): List<T> { return mutableListOf<T>().apply(init) } fun main() { val list = buildList<Int> { add(1) add(2) } } これによって1.3より前で
  52. Inference for builder lambdas @UseExperimental(ExperimentalTypeInference::class) fun <T> buildList( @BuilderInference init:

    MutableList<T>.() -> Unit ): List<T> { return mutableListOf<T>().apply(init) } fun main() { val list = buildList { add(1) add(2) } } Intを省略可能
  53. Inference for call chains fun createMap(): Map<String, Int> = MapBuilder()

    .put("answer", 42) .build() MapBuilderは自分で定義した関数? (発表資料ままです) Kotlin 1.2: One call is analyzed at a time
 Kotlin 1.3: A call chain is analyzed
  54. Inference for call chains fun createMap() = MapBuilder() .put("answer", 42)

    .build() Kotlin1.3からは全体で評価されるので型定義を省略可能
  55. Intersection types interface Foo interface Bar fun <T> hoge(thing: T)

    where T : Foo, T : Bar { println(thing) } fun better() { val something: Better = Better.A if (something is Foo && something is Bar) { hoge(something) // Foo & Bar } } sealed class Better { object A : Better() object B : Better(), Foo object C : Better(), Foo, Bar }
  56. Intersection types interface Foo interface Bar fun <T> hoge(thing: T)

    where T : Foo, T : Bar { println(thing) } fun better() { val something: Better = Better.A if (something is Foo && something is Bar) { hoge(something) // Foo & Bar } } sealed class Better { object A : Better() object B : Better(), Foo object C : Better(), Foo, Bar }
  57. Intersection types interface Foo interface Bar fun <T> hoge(thing: T)

    where T : Foo, T : Bar { println(thing) } fun better() { val something: Better = Better.A if (something is Foo && something is Bar) { hoge(something) // Foo & Bar } } sealed class Better { object A : Better() object B : Better(), Foo object C : Better(), Foo, Bar } somethingは Foo & Barと判定しているが…
  58. Intersection types interface Foo interface Bar fun <T> hoge(thing: T)

    where T : Foo, T : Bar { println(thing) } fun better() { val something: Better = Better.A if (something is Foo && something is Bar) { hoge(something) // Compile error } } sealed class Better { object A : Better() object B : Better(), Foo object C : Better(), Foo, Bar } Kotlin1.2まではコンパイルエラーだった
  59. Intersection types interface Foo interface Bar fun <T> hoge(thing: T)

    where T : Foo, T : Bar { println(thing) } fun better() { val something: Better = Better.A if (something is Foo && something is Bar) { hoge(something) // Foo & Bar } } sealed class Better { object A : Better() object B : Better(), Foo object C : Better(), Foo, Bar } 1.3からはコンパイル可
  60. 4VNNBSZ Summary

  61. Summary • Experimentalの役割がより明確に • Kotlin1.3は痒かったところに手が届く
 - Contracts
 - SAM
 -

    Inference • KotlinConf 凄く良かった
 個人的にはKotlin Nativeを激推ししていきたい
  62. AAkira @_a_akira Have a nice Kotlin