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

What's up next for Kotlin? RC Edition

What's up next for Kotlin? RC Edition

There's probably never been a better moment for the Kotlin ecosystem, and the language is getting ready to become The "write once, run everywhere" solution. Let's walk through some of the features of the upcoming Kotlin release (1.3), to see what the Kotlin future might look like.

Nicola Corti

October 27, 2018
Tweet

More Decks by Nicola Corti

Other Decks in Technology

Transcript

  1. 1.3

  2. 1.3

  3. 1.3

  4. Capturing When fun Request.getBody() : ResponseBody { val response =

    executeRequest() when (response) { is Authenticator.Success -> response.body is HttpError -> throw HttpException(response.status) } }
  5. Capturing When fun Request.getBody() : ResponseBody { when (val response

    = executeRequest()) { is Authenticator.Success -> response.body is HttpError -> throw HttpException(response.status) } }
  6. Capturing When fun Request.getBody() = when (val response = executeRequest())

    { is Authenticator.Success -> response.body is HttpError -> throw HttpException(response.status) }
  7. Arity fun arity22Function(lambda : ( Int, Int, Int, Int, Int,

    Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) -> Unit) { }
  8. Arity fun arity22Function(lambda : ( Int, Int, Int, Int, Int,

    Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) -> Unit) { } public final void arity22Function(@NotNull Function22 lambda) { Intrinsics.checkParameterIsNotNull(lambda, "lambda"); }
  9. Arity package kotlin.jvm.functions /** A function that takes 0 arguments.

    */ public interface Function0<out R> : Function<R> { /** Invokes the function. */ public operator fun invoke(): R } /** A function that takes 1 argument. */ public interface Function1<in P1, out R> : Function<R> { /** Invokes the function with the specified argument. */ public operator fun invoke(p1: P1): R } /** A function that takes 2 arguments. */ public interface Function2<in P1, in P2, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2): R } /** A function that takes 3 arguments. */ public interface Function3<in P1, in P2, in P3, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3): R } /** A function that takes 4 arguments. */ public interface Function4<in P1, in P2, in P3, in P4, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4): R } /** A function that takes 5 arguments. */ public interface Function5<in P1, in P2, in P3, in P4, in P5, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5): R } /** A function that takes 6 arguments. */ public interface Function6<in P1, in P2, in P3, in P4, in P5, in P6, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6): R } /** A function that takes 7 arguments. */ public interface Function7<in P1, in P2, in P3, in P4, in P5, in P6, in P7, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7): R } /** A function that takes 8 arguments. */ public interface Function8<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8): R } /** A function that takes 9 arguments. */ public interface Function9<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9): R } /** A function that takes 10 arguments. */ public interface Function10<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10): R } /** A function that takes 11 arguments. */ public interface Function11<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, out R> : Function<R> {
  10. Arity /** A function that takes 8 arguments. */ public

    interface Function8<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8): R } /** A function that takes 9 arguments. */ public interface Function9<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9): R } /** A function that takes 10 arguments. */ public interface Function10<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10): R } /** A function that takes 11 arguments. */ public interface Function11<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11): R } /** A function that takes 12 arguments. */ public interface Function12<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12): R } /** A function that takes 13 arguments. */ public interface Function13<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13): R } /** A function that takes 14 arguments. */ public interface Function14<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, in P14, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14): R } /** A function that takes 15 arguments. */ public interface Function15<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, in P14, in P15, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15): R } /** A function that takes 16 arguments. */ public interface Function16<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, in P14, in P15, in P16, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16): R } /** A function that takes 17 arguments. */ public interface Function17<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, in P14, in P15, in P16, in P17, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17): R } /** A function that takes 18 arguments. */ public interface Function18<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, in P14, in P15, in P16, in P17, in P18, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18): R } /** A function that takes 19 arguments. */ public interface Function19<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, in P14, in P15, in P16, in P17, in P18, in P19, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18, p19: P19): R } /** A function that takes 20 arguments. */ public interface Function20<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, in P14, in P15, in P16, in P17, in P18, in P19, in P20, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18, p19: P19, p20: P20): R } /** A function that takes 21 arguments. */ public interface Function21<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, in P14, in P15, in P16, in P17, in P18, in P19, in P20, in P21, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18, p19: P19, p20: P20, p21: P21): R } /** A function that takes 22 arguments. */ public interface Function22<in P1, in P2, in P3, in P4, in P5, in P6, in P7, in P8, in P9, in P10, in P11, in P12, in P13, in P14, in P15, in P16, in P17, in P18, in P19, in P20, in P21, in P22, out R> : Function<R> { /** Invokes the function with the specified arguments. */ public operator fun invoke(p1: P1, p2: P2, p3: P3, p4: P4, p5: P5, p6: P6, p7: P7, p8: P8, p9: P9, p10: P10, p11: P11, p12: P12, p13: P13, p14: P14, p15: P15, p16: P16, p17: P17, p18: P18, p19: P19, p20: P20, p21: P21, p22: P22): R }
  11. Arity fun arity22Function(lambda : ( Int, Int, Int, Int, Int,

    Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) -> Unit) { }
  12. Arity fun arity23Function(lambda : ( Int, Int, Int, Int, Int,

    Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) -> Unit) { }
  13. Arity fun arity23Function(lambda : ( Int, Int, Int, Int, Int,

    Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) -> Unit) { } public final void arity23Function(@NotNull FunctionN lambda) { Intrinsics.checkParameterIsNotNull(lambda, "lambda"); }
  14. Arity fun arity23Function(lambda : ( Int, Int, Int, Int, Int,

    Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int, Int) -> Unit) { } public final void arity23Function(@NotNull FunctionN lambda) { Intrinsics.checkParameterIsNotNull(lambda, "lambda"); }
  15. Arity @SinceKotlin("1.3") interface FunctionN<out R> : Function<R>, FunctionBase<R> { /**

    * Invokes the function with the specified arguments. * * Must **throw exception** if the length of passed [args] * is not equal to the parameter count returned by [arity]. * * @param args arguments to the function */ operator fun invoke(vararg args: Any?): R /** * Returns the number of arguments that must be passed to * this function. */ override val arity: Int } http://bit.ly/keep-bigarity
  16. Inline Classes inline class Username(val value: String) inline class Password(val

    value: String) val myName = Username("nicola") val myPassword = Password("p4ssw0rd")
  17. Inline Classes inline class Username(val value: String) inline class Password(val

    value: String) val myName = Username("nicola") val myPassword = Password("p4ssw0rd") myName = myPassword
  18. Inline Classes inline class Username(val value: String) inline class Password(val

    value: String) val myName = Username("nicola") val myPassword = Password("p4ssw0rd") myName = myPassword myPassword = myName
  19. Inline Classes inline class Username(val value: String) inline class Password(val

    value: String) val myName = Username("nicola") val myPassword = Password("p4ssw0rd") myName = myPassword myPassword = myName myName = "MyNewName" bit.ly/keep-inlineclasses
  20. Unsigned Types val anUnsignedInteger : UInt val anUnsignedLong : ULong

    val anUnsignedByte : UByte val anUnsignedShort : UShort
  21. Unsigned Types val anUnsignedInteger : UInt = 0xFFFF_FFFFu val anUnsignedLong

    : ULong = 10uL val anUnsignedByte : UByte = 0xFFu val anUnsignedShort : UShort = 0xFFFFu
  22. Result /** * A discriminated union that encapsulates successful outcome

    * with a value of type [T] or a failure with an arbitrary * [Throwable] exception. */ inline class Result<out T> internal constructor( internal val value: Any? // internal value -- either T or Failure ) { internal class Failure(val exception: Throwable) //... }
  23. Result /** * A discriminated union that encapsulates successful outcome

    * with a value of type [T] or a failure with an arbitrary * [Throwable] exception. */ inline class Result<out T> internal constructor( internal val value: Any? // internal value -- either T or Failure ) { internal class Failure(val exception: Throwable) //... }
  24. Result /** * A discriminated union that encapsulates successful outcome

    * with a value of type [T] or a failure with an arbitrary * [Throwable] exception. */ inline class Result<out T> internal constructor( internal val value: Any? // internal value -- either T or Failure ) { internal class Failure(val exception: Throwable) //... }
  25. Result /** * A discriminated union that encapsulates successful outcome

    * with a value of type [T] or a failure with an arbitrary * [Throwable] exception. */ inline class Result<out T> internal constructor( internal val value: Any? // internal value -- either T or Failure ) { internal class Failure(val exception: Throwable) //... } inline fun <R> runCatching(block: () -> R): Result<R>
  26. Result /** * A discriminated union that encapsulates successful outcome

    * with a value of type [T] or a failure with an arbitrary * [Throwable] exception. */ inline class Result<out T> internal constructor( internal val value: Any? // internal value -- either T or Failure ) { internal class Failure(val exception: Throwable) //... } inline fun <R> runCatching(block: () -> R): Result<R>
  27. Result inline fun <R> runCatching(block: () -> R): Result<R> {

    return try { Result.success(block()) } catch (e: Throwable) { Result.failure(e) } }
  28. Result sealed class FindUserResult { data class Found(val user: User)

    : FindUserResult() data class NotFound(val name: String) : FindUserResult() data class MalformedName(val name: String) : FindUserResult() // other cases that need different business-specific handling code } fun findUserByName(name: String): FindUserResult
  29. Result - Use Cases try { val data = doSomething()

    processData(data) } catch(e: Throwable) { showErrorDialog(e) }
  30. Result - Use Cases try { val data = doSomething()

    processData(data) } catch(e: Throwable) { showErrorDialog(e) } runCatching { doSomething() } .onFailure { showErrorDialog(it) } .onSuccess { processData(it) }
  31. Result - Use Cases /** * Interface representing a continuation

    after a suspension point that * returns value of type `T`. */ @SinceKotlin("1.3") public interface Continuation<in T> { /** * Context of the coroutine that corresponds to this continuation. */ public val context: CoroutineContext /** * Resumes the execution of the corresponding coroutine passing successful or failed [result] as the * return value of the last suspension point. */ public fun resumeWith(result: Result<T>) } bit.ly/keep-result
  32. The Problem @Test fun testMyTokenLength() { val token : String?

    = getMyToken(); assertNotNull(token) assertEquals(42, token.length) } Error(5, 22): Only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver of type String?
  33. The Problem @Test fun testMyTokenLength() { val token : String?

    = getMyToken(); assertNotNull(token) assertEquals(42, token?.length) }
  34. Kotlin Contracts • The Compiler is not smart enough to


    understand the context • You know something that the compiler doesn’t know • We can provide this extra knowledge with a Kotlin Contract • The goal is to write better/cleaner code
  35. Syntax fun Int?.isValid(): Boolean { contract { // Place your

    effects here } return this != null && this != 0 }
  36. Returns fun returns(): SimpleEffect fun returns(value: Any?): SimpleEffect fun returnsNotNull():

    SimpleEffect interface SimpleEffect : Effect { infix fun implies(boolExpr: Boolean): ConditionalEffect } ConditionalEffect
  37. Syntax val aInt : Int? = getAnInt() if (aInt.isValid()){ //

    Here the compiler knows that `aInt` is not nullable // thanks to the contract on `isValid` aInt.absoluteValue } else { }
  38. Syntax val aInt : Int? = getAnInt() if (aInt.isValid()){ //

    Here the compiler knows that `aInt` is not nullable // thanks to the contract on `isValid` aInt.absoluteValue } else { // Here the compiler has no extra information since // the `isValid` has only a `returns(true)` effect aInt?.absoluteValue }
  39. The Problem @Test fun testMyTokenLenght() { val token : String?

    = getMyToken(); assertNotNull(token) assertEquals(42, token?.length) }
  40. The Problem @Test fun testMyTokenLenght() { val token : String?

    = getMyToken(); assertNotNull(token) assertEquals(42, token.length) }
  41. The Problem fun assertNotNull(actual: Any?) { contract { returns() implies

    (actual != null) } org.junit.Assert.assertNotNull(actual) }
  42. CallsInPlace • lambda will not be called after the call

    to owner-function is finished. • lambda will not be passed to another function that 
 doesn’t have a similar contract. • lambda will be called the specified amount of times (kind) fun <R> callsInPlace( lambda: Function<R>, kind: InvocationKind = InvocationKind.UNKNOWN ): CallsInPlace
  43. CallsInPlace fun main(){ val x : Int? run { x

    = 10 } println(x) } Error:(6, 18) Variable ‘x’ must be initialized Error:(4, 8) Captured values initialization is forbidden due to possible reassignment
  44. CallsInPlace public inline fun <T, R> T.run(block: T.() -> R):

    R { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } return block() }
  45. Limitations • They are not verified. 
 You’re responsible for

    writing correct contracts. • returns(value) and implies allowed values are limited • Only to top-level and block functions.
  46. To infinity… • Collections Literals • SAM Conversion • Truly

    Immutability val list = listOf("1", "2", "3") val list = ["1", "2", "3"] val map = mapOf("1" to 1, "2" to 2, "3" to 3) val map = ["1" = 1, "2" = 2, "3" = 3] interface Function<T> { fun run(data: T) } val myFunction: Function<String> = { println ("data $it”) } class Foo(var v: Int) immutable class Bar(val foo: Foo) // This should fail bit.ly/kotlin-feature-survey