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

New Features in Kotlin 1.1

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.
Avatar for GDG SPb GDG SPb
March 15, 2017

New Features in Kotlin 1.1

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

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

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

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

Avatar for GDG SPb

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