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

New features in Kotlin 1.1 and what's next

New features in Kotlin 1.1 and what's next

This talk will be an introduction into Kotlin new features which will be released in version 1.1. We will consider use-cases and real examples where applying new features will make your code more precise and brief. We will also talk about our future plans concerning further development of Kotlin.

Stanislav Erokhin

October 14, 2016
Tweet

Other Decks in Programming

Transcript

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

    ) fun getPerson(): Person { return Person("John", "London") } fun sayHello() { val (name, city) = getPerson() println("Hello $name from $city") }
  2. Destructuring data class Person( val name: String, val city: String

    ) fun getPerson(): Person { return Person("John", "London") } fun sayHello() { val (name, city) = getPerson() println("Hello $name from $city") }
  3. Destructuring data class Person( val name: String, val city: String

    ) fun getPerson(): Person { return Person("John", "London") } fun sayHello() { val (name, city) = getPerson() println("Hello $name from $city") }
  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 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") } }
  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. 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") } }
  8. Underscore for unused parameters fun addListener( listener: (String, Int, error:

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

    String?) -> Unit ) { … } … addListener { _, _, error -> if (error != null) println(error) }
  10. 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") }
  11. Data classes data class Person( val name: String, val city:

    String, val age: Int ) Generated methods: • toString • equals / hashCode • componentN • copy
  12. 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) } }
  13. 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
  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 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 ) { … }
  16. 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) { … }
  17. 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) { … }
  18. Type aliases typealias MyString = String fun foo(s: MyString) =

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

    println(s) fun bar(s: String) = foo(s) Same type
  20. 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>>
  21. Coroutines asyncUI { val image = await(loadImage()) panel.setImage(image) } loadImage().whenComplete

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

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

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

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

    } } asyncUI { val image = await(loadImage()) val resizedImage = await(resize(image)) panel.setImage(image) }
  26. Coroutines loadImage().whenComplete { image -> resize(image).whenComplete { resizedImage -> panel.setImage(resizedImage)

    } } asyncUI { val image = await(loadImage()) val resizedImage = await(resize(image)) panel.setImage(image) } 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. 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") }
  33. Library code: await() fun work(): CompletableFuture<String> = … fun moreWork()

    = async { println("Work started") val str = await(work()) println("Work completed: $str") }
  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>, machine: Continuation<V>) { f.whenComplete { value, throwable -> if (throwable == null) machine.resume(value) else machine.resumeWithException(throwable) } }
  35. 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>, machine: Continuation<V>) { f.whenComplete { value, throwable -> if (throwable == null) machine.resume(value) else machine.resumeWithException(throwable) } }
  36. 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>, machine: Continuation<V>) { f.whenComplete { value, throwable -> if (throwable == null) machine.resume(value) else machine.resumeWithException(throwable) } }
  37. 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>, machine: Continuation<V>) { f.whenComplete { value, throwable -> if (throwable == null) machine.resume(value) else machine.resumeWithException(throwable) } }
  38. 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>, machine: Continuation<V>) { f.whenComplete { value, throwable -> if (throwable == null) machine.resume(value) else machine.resumeWithException(throwable) } }
  39. 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()) }
  40. 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
  41. Summary: coroutines • Asynchronous programming - async/await and more •

    Lazy generators - yield • Maximum flexibility for library designers • Example library: - https://github.com/Kotlin/kotlinx.coroutines
  42. 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 }
  43. Delegated properties class Foo { val text: String by lazy

    { computeText() } private fun computeText(): String { … } }
  44. 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!! } }
  45. 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!! } }
  46. Delegated properties interface ResourceLoader<T> { operator fun getValue( thisRef: Any?,

    property: KProperty<*> ): T } fun <T> bindResource( id: ResourceID<T> ): ResourceLoader<T> { ... } class MyUI { val image by bindResource(image_id) val text by bindResource(text_id) }
  47. Delegated properties interface ResourceLoader<T> { operator fun getValue( thisRef: Any?,

    property: KProperty<*> ): T } fun <T> bindResource( id: ResourceID<T> ): ResourceLoader<T> { ... } class MyUI { val image by bindResource(image_id) val text by bindResource(text_id) }
  48. Delegated properties interface ResourceLoader<T> { operator fun getValue( thisRef: Any?,

    property: KProperty<*> ): T } fun <T> bindResource( id: ResourceID<T> ): ResourceLoader<T> { ... } class MyUI { val image by bindResource(image_id) val text by bindResource(text_id) }
  49. Local delegated properties fun main(args: Array<String>) { val text by

    lazy { "Hello world!" } if (Math.random() > 0.5) { println(text) } }
  50. 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)
  51. 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 }
  52. 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 }
  53. 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>
  54. 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"))
  55. 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>
  56. Bound member references class MyModel { fun initialize(button: JButton) {

    button.addActionListener(this::buttonAction) } fun buttonAction(e: ActionEvent) { … } }
  57. 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")
  58. 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")
  59. 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")
  60. 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
  61. 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 } getNames().set(1, "Ivan")
  62. 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 } getNames().set(1, "Ivan")
  63. 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 } getNames().set(1, "Ivan") Compilation Error
  64. 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>
  65. Java 8 default methods fun test(c: Collection<Int>) { c.stream() }

    kotlin.collections.Collection java.util.Collection.stream
  66. 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> { … } }
  67. 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> { … } }
  68. References • https://kotlinlang.org/ • Language Design Proposals (KEEP) – https://github.com/Kotlin/KEEP

    – Give your feedback in GitHub Issues • Issue tracker – https://youtrack.jetbrains.com/issues/KT
  69. JVM Target interface A { fun foo() {} } -jvm-target=1.8

    // ===A.class== // class version 52.0 (52) public abstract interface A { // access flags 0x1 public default foo()V … }
  70. Library code: async() fun work()/*: CompletableFuture<String>*/ = … fun moreWork()

    = async { println("Work started") val str = await(work()) println("Work completed: $str") } fun <T> async( coroutine c: FutureController<T>.() → Continuation<Unit> ): CompletableFuture<T> { val controller = FutureController<T>() c(controller).resume(Unit) return controller.future }