Upgrade to Pro — share decks privately, control downloads, hide ads and more …

2018-10-15-kotlin13

AAkira
October 15, 2018

 2018-10-15-kotlin13

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

AAkira

October 15, 2018
Tweet

More Decks by AAkira

Other Decks in Technology

Transcript

  1. 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.
  2. Experimental features Purpose To let new features be tried by

    early adopters 
 as soon as possible
  3. Experimental features @ShinyNewAPI fun doSomething() { val foo = Foo()

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

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

    foo.bar() } @ShinyNewAPI fun main() { doSomething() }
  6. 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
  7. 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
  8. 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”
  9. 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()
  10. 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()
  11. Contracts • can be implicitly changed • can implicitly break

    code depending on it なぜコンパイラはrun内で代入されたhogeがnon-nullなのを理解出来ないのか
  12. 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() コンパイラに一度だけ実行されるという情報を
 教えてあげる
  13. Contracts Kotlin 1.3より前では実行出来ない fun main(args: Array<String>) {
 val s :

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

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

    String? = "" if(!s.isNullOrEmpty()) { s.first() }
 }
  17. 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()) } }
  18. 自作も可能 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が必要
  19. 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で書き換え可能
  20. 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で書き換え可能
  21. 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が不要
  22. Contracts • run, let, with, apply, also, takeIf, takeUnless, synchronized

    • isNullOrEmpty, isNullOrBlank, • kotlin.test: assertTrue, assertFalse, assertNotNull • check, checkNotNull, require, requireNotNull Contractが追加されたメソッド達
  23. New type inference • SAM conversions for Kotlin functions •

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

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

    .java fun handleInput(handler: Action<String>) { ... } fun main() {
 handleInput { println(it) } } .kt 1.3からはこう書ける
  26. 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) で回避していた
  27. SAM conversions val obs = Observable.just(100) Observable.just(1) .zipWith(obs) { a,

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

    print("hoge") yield(4) } Kotlin1.3から型パラメータが不要
  29. 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) } } もちろん自分でも定義可能
  30. 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を使う
  31. 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を使う
  32. 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より前で
  33. 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を省略可能
  34. 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
  35. Inference for call chains fun createMap() = MapBuilder() .put("answer", 42)

    .build() Kotlin1.3からは全体で評価されるので型定義を省略可能
  36. 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 }
  37. 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 }
  38. 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と判定しているが…
  39. 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まではコンパイルエラーだった
  40. 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からはコンパイル可
  41. Summary • Experimentalの役割がより明確に • Kotlin1.3は痒かったところに手が届く
 - Contracts
 - SAM
 -

    Inference • KotlinConf 凄く良かった
 個人的にはKotlin Nativeを激推ししていきたい