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

New Features in Kotlin 1.1

GDG SPb
March 15, 2017

New Features in Kotlin 1.1

Видео: https://youtu.be/YqXc8QQNIGc

Узнайте, что же нового в релизе 1.1. Будут рассмотрены реальные примеры использования новых фич языка, а также показаны ситуации, в которых эти фичи помогут сделать ваш код более выразительным и кратким. Также будет рассказано о планах развития языка.

Автор: Станислав Ерохин

Работает в команде Kotlin 3.5 года, занимается компилятором и всякими теоретическими задачами, которые возникают по ходу. Интересуется формальными системами типов, выводом типов. Активно участвует в дизайне новых фич.

GDG SPb

March 15, 2017
Tweet

More Decks by GDG SPb

Other Decks in Technology

Transcript

  1. Destructuring data class Person( val name: String, val city: String

    ) fun getPerson()/*: Person */ = Person("Ivan", "SPb")
  2. Destructuring data class Person( val name: String, val city: String

    ) fun getPerson()/*: Person */ = Person("Ivan", "SPb") fun sayHello() { val (name, city) = getPerson() println("Hello $name from $city") }
  3. Destructuring fun helloAll(nameToCity: Map<String, String>) { for (entry in nameToCity)

    { println("Hello ${entry.key} from ${entry.value}") } }
  4. Destructuring fun helloAll(nameToCity: Map<String, String>) { for (entry in nameToCity)

    { println("Hello ${entry.key} from ${entry.value}") } } fun helloAll(nameToCity: Map<String, String>) { for ((name, city) in nameToCity) { println("Hello $name from $city") } }
  5. Destructuring for lambdas data class Person( val name: String, val

    city: String, val age: Int ) fun sayHelloToChildren(persons: List<Person>) { val children = persons.filter { person -> person.age < 18 } children.forEach { (name, city) -> println("Hello $name from $city") } }
  6. Destructuring for lambdas data class Person( val name: String, val

    city: String, val age: Int ) fun sayHelloToChildren(persons: List<Person>) { val children = persons.filter { person -> person.age < 18 } children.forEach { (name, city) -> println("Hello $name from $city") } }
  7. Underscore for unused parameters fun addListener( listener: (String, Int, error:

    String?) -> Unit ) { … } … addListener { data, code, error -> if (error != null) println(error) }
  8. Underscore for unused parameters fun addListener( listener: (String, Int, error:

    String?) -> Unit ) { … } … addListener { _, _, error -> if (error != null) println(error) }
  9. Underscore for unused parameters data class Person( val name: String,

    val city: String, val age: Int ) val persons: List<Person> = … persons.forEach { (name, _, age) -> println("$name is $age years old") }
  10. Data classes data class Person( val name: String, val city:

    String, val age: Int ) Generated methods: • toString • equals / hashCode • componentN • copy
  11. Sealed classes sealed class Expr { class Num(val value: Int):

    Expr() class Sum(val left: Expr, val right: Expr): Expr() } fun eval(e: Expr): Int { when (e) { is Expr.Num -> return e.value is Expr.Sum -> return eval(e.left) + eval(e.right) } }
  12. Sealed & data classes sealed class Expr { class Num(val

    value: Int): Expr() data class Sum( val left: Expr, val right: Expr ): Expr() } sealed data 1.1
  13. Type aliases fun foo( data: String, handler: (Int, String, Any)

    -> Unit ) { … } fun bar( code: Int, handler: (Int, String, Any) -> Unit ) { … } fun baz( obj: Any, handler: (Int, String, Any) -> Unit ) { … }
  14. Type aliases fun foo( data: String, handler: (Int, String, Any)

    -> Unit ) { … } fun bar( code: Int, handler: (Int, String, Any) -> Unit ) { … } fun baz( obj: Any, handler: (Int, String, Any) -> Unit ) { … }
  15. Type aliases typealias MyHandler = (Int, String, Any) -> Unit

    fun foo(data: String, handler: MyHandler) { … } fun bar(code: Int, handler: MyHandler) { … } fun baz(obj: Any, handler: MyHandler) { … }
  16. Type aliases typealias MyString = String fun foo(s: MyString) =

    println(s) fun bar(s: String) = foo(s) Same type
  17. Type aliases typealias MyString = String fun foo(s: MyString) =

    println(s) fun bar(s: String) = foo(s) Same type
  18. Type aliases typealias MyHandler = (Int, String, Any) -> Unit

    typealias Predicate<T> = (T) -> Boolean typealias NodeSet = Set<Node> typealias FileTable<K> = Map<K, List<File>> typealias EdgeMap<N> = Map<N, List<N>>
  19. Asynchronous computations loadImage().whenCompete { image, e -> invokeLater { panel.setImage(image)

    } } fun loadImage(): CompletableFuture<Image> IO Thread AWT Thread
  20. Asynchronous computations loadImage().whenComplete { image -> resizeThenRun(image) { resizedImage ->

    invokeLater { panel.setImage(resizedImage) } } } IO Thread AWT Thread
  21. Asynchronous computations loadImage().whenComplete { image -> resizeThenRun(image) { resizedImage ->

    invokeLater { panel.setImage(resizedImage) } } } IO Thread AWT Thread Other thread
  22. Coroutines asyncUI { val image = await(loadImage()) panel.setImage(image) } loadImage().whenComplete

    { image -> panel.setImage(image) } Time-consuming operation Callback
  23. Coroutines asyncUI { val image = await(loadImage()) panel.setImage(image) } loadImage().whenComplete

    { image -> panel.setImage(image) } Time-consuming operation Continuation Callback
  24. Coroutines asyncUI { val image = await(loadImage()) panel.setImage(image) } loadImage().whenComplete

    { image -> panel.setImage(image) } Time-consuming operation Continuation Suspending call Callback
  25. Coroutines asyncUI { val image = await(loadImage()) panel.setImage(image) } loadImage().whenComplete

    { image -> panel.setImage(image) } Time-consuming operation Continuation Suspending call Callback Coroutine
  26. Coroutines loadImage().whenComplete { image -> resizeThenRun(image) { resizedImage -> invokeLater

    { panel.setImage(resizedImage) } } } asyncUI { val image = await(loadImage()) val resizedImage = await(resize(image)) invokeLater { panel.setImage(resizedImage) } } Suspending calls
  27. C# Way async Task<String> work() { Thread.sleep(200); return "done"; }

    async Task moreWork() { Console.WriteLine("Work started"); var str = await work(); Console.WriteLine($"Work completed:{str}"); }
  28. C# Way async Task<String> work() { Thread.sleep(200); return "done"; }

    async Task moreWork() { Console.WriteLine("Work started"); var str = await work(); Console.WriteLine($"Work completed:{str}"); }
  29. C# Way async Task<String> work() { Thread.sleep(200); return "done"; }

    async Task moreWork() { Console.WriteLine("Work started"); var str = await work(); Console.WriteLine($"Work completed:{str}"); }
  30. Kotlin Way fun work()/*: CompletableFuture<String>*/ = async { Thread.sleep(200) "done"

    } fun moreWork() = async { println("Work started") val str = await(work()) println("Work completed: $str") }
  31. Kotlin Way fun work()/*: CompletableFuture<String>*/ = async { Thread.sleep(200) "done"

    } fun moreWork() = async { println("Work started") val str = await(work()) println("Work completed: $str") }
  32. Library code: await() fun work(): CompletableFuture<String> = … fun moreWork()

    = async { println("Work started") val str = await(work()) println("Work completed: $str") } suspend fun <V> await(f: CompletableFuture<V>): V = suspendCoroutine { machine: Continuation<V> -> f.whenComplete { value, throwable -> if (throwable == null) machine.resume(value) else machine.resumeWithException(throwable) } }
  33. Library code: await() fun work(): CompletableFuture<String> = … fun moreWork()

    = async { println("Work started") val str = await(work()) println("Work completed: $str") } suspend fun <V> await(f: CompletableFuture<V>): V = suspendCoroutine { machine: Continuation<V> -> f.whenComplete { value, throwable -> if (throwable == null) machine.resume(value) else machine.resumeWithException(throwable) } }
  34. Library code: await() fun work(): CompletableFuture<String> = … fun moreWork()

    = async { println("Work started") val str = await(work()) println("Work completed: $str") } suspend fun <V> await(f: CompletableFuture<V>): V = suspendCoroutine { machine: Continuation<V> -> f.whenComplete { value, throwable -> if (throwable == null) machine.resume(value) else machine.resumeWithException(throwable) } }
  35. Generators fun main(args: Array<String>) { val sequence/*: Sequence<Int>*/ = generate

    { yield(1) yield(2) for (i in 3..5) { yield(i) } yield(6) } println(sequence.joinToString()) }
  36. Generators fun main(args: Array<String>) { val sequence/*: Sequence<Int>*/ = generate

    { yield(1) yield(2) for (i in 3..5) { yield(i) } yield(6) } println(sequence.joinToString()) } suspend calls
  37. Summary: coroutines • Asynchronous programming - async/await and more •

    Lazy generators - yield • Maximum flexibility for library designers • Example library: - https://github.com/Kotlin/kotlinx.coroutines
  38. Shorter syntax for properties data class Person( val name: String,

    val age: Int ) { // Property type inferred to be 'Boolean' val isAdult get() = age >= 18 } var Person.city get() = "SPb" set(value) = ...
  39. enumValues inline fun <reified E: Enum<E>> printAll() { enumValues<E>().forEach(::println) }

    inline fun <reified E: Enum<E>> getOKEntry(): E { return enumValueOf<E>("OK") }
  40. Delegated properties 1 class Foo { 2 private var text:

    String? = null 3 4 private fun computeText(): String { … } 5 6 fun getText(): String { 7 if (text == null) { 8 text = computeText() 9 } 10 return text!! 11 } 12 }
  41. Delegated properties class Foo { val text/*: String*/ by lazy

    { … } } class OldFoo { private var text: String? = null private fun computeText(): String { … } fun getText(): String { if (text == null) { text = computeText() } return text!! } }
  42. Local delegated properties fun main(args: Array<String>) { val text by

    lazy { "Hello world!" } if (Math.random() > 0.5) { println(text) } }
  43. Inline accessors and const val’s val <T> List<T>.lastIndex: Int inline

    get() = this.size - 1 const val SIZE = 10 fun main(args: Array<String>) { val lastIndex = (1..SIZE).toList().lastIndex println(lastIndex) }
  44. Class Literal class Foo fun bar(n: Number) { val fooClass

    = Foo::class val kclass = n::class println(fooClass.simpleName) // "Foo" println(kClass.simpleName) // "Int" } fun main(args: Array<String>) = bar(4)
  45. Bound member reference data class Person(val name: String) fun doSomething(person:

    Person) { val kProp = person::name computeAndPrint(kProp) println(kProp()) } fun computeAndPrint(c: () -> String) = println(c()) KProperty0<String>
  46. Member reference data class Person( val name: String, val city:

    String ) fun doSomething(persons: List<Person>) { val names = persons.map(Person::name) … } KProperty1<Person, String>
  47. Member reference data class Person( val name: String, val city:

    String ) fun doSomething(persons: List<Person>) { val names = persons.map(Person::name) … } persons.map { p -> p.name } KProperty1<Person, String>
  48. Bound member reference data class Person(val name: String) fun doSomething(person:

    Person) { val kProp = person::name computeAndPrint(kProp) // "Ivan" println(kProp()) // "Ivan" } fun computeAndPrint(c: () -> String) = println(c()) doSomething(Person("Ivan")) KProperty0<String>
  49. Bound member references class MyModel { fun initialize(button: JButton) {

    button.addActionListener(this::buttonAction) } fun buttonAction(e: ActionEvent) { … } }
  50. JDK Collections interface List<E> { E get(int index) E set(

    int index, E element ) } /* Read Only */ List<String> getNames() { List<String> l = …; return unmodifiableList(l); }
  51. JDK Collections interface List<E> { E get(int index) E set(

    int index, E element ) } /* Read Only */ List<String> getNames() { List<String> l = …; return unmodifiableList(l); } getNames().set(1, "Ivan") UnsupportedOperationException
  52. Cool Collections interface List<E> { E get(int index) } interface

    MutableList<E> extends List<E> { E set(int index, E element) } List<String> getNames() { List<String> l = …; return l; // may be mutable }
  53. Cool Collections interface List<E> { E get(int index) } interface

    MutableList<E> extends List<E> { E set(int index, E element) } Compilation Error List<String> getNames() { List<String> l = …; return l; // may be mutable } getNames().set(1, "Ivan")
  54. Kotlin Collections Iterable<out T> Iterable<out T> Collection<out T> Collection<out T>

    List<out T> List<out T> Set<out T> Set<out T> MutableIterable<T> MutableIterable<T> MutableCollection<T> MutableCollection<T> MutableList<T> MutableList<T> MutableSet<T> MutableSet<T> java.lang.ArrayList<T> java.lang.ArrayList<T> java.util.HashSet<T> java.util.HashSet<T>
  55. Java 8 default methods fun test(c: Collection<Int>) { c.stream() }

    kotlin.collections.Collection java.util.Collection.stream
  56. Java 8 default methods package java.util interface Collection<E> { default

    Stream<E> stream() { … } } package kotlin.collections interface Collection<out E> { fun stream(): Stream<E> { … } } 1.1
  57. References • https://kotlinlang.org/ • https://kotlinlang.slack.com/ • Language Design Proposals (KEEP)

    – https://github.com/Kotlin/KEEP – Give your feedback in GitHub Issues • Issue tracker – https://youtrack.jetbrains.com/issues/KT