What's New in Kotlin 1.3? - Chicago Kotlin User Group

What's New in Kotlin 1.3? - Chicago Kotlin User Group

Kotlin 1.3 is finally here and all of the new features aren't going to explain themselves. I gave this presentation to the Chicago Kotlin User Group on 2018-11-20.

2777430c1f9869e411ab5d8b17d8ba2a?s=128

Todd Ginsberg

November 20, 2018
Tweet

Transcript

  1. What’s New In Kotlin 1.3? Chicago Kotlin User Group 2018-11-20

    Todd Ginsberg @ToddGinsberg Principal Software Developer
  2. @ToddGinsberg Who Is This Person? Todd Ginsberg Principal Software Developer

    @Netspend (a payments company in Austin, TX) Chicago Java User Group Community Director and CFO
  3. @ToddGinsberg What’s New?

  4. @ToddGinsberg Start at the Beginning… fun main(args: Array<String>) { }

  5. @ToddGinsberg Start at the Beginning… fun main() { }

  6. @ToddGinsberg Capture the Subject of When val answer = theAnswer()

    return when(answer) { 42 -> "You got the right answer!" else -> "Sorry, $answer is not correct" }
  7. @ToddGinsberg Capture the Subject of When when(val answer = theAnswer())

    { 42 -> "You got the right answer!" else -> "Sorry, $answer is not correct" }
  8. @ToddGinsberg Function: associateWith() val people = listOf("Alice", "Bob", "Charlie") val

    nameAndLength: Map<String, Int> = people.associate { it to it.length }
  9. @ToddGinsberg Function: associateWith() val people = listOf("Alice", "Bob", "Charlie") val

    nameAndLength: Map<String, Int> = people.associateWith { it.length }
  10. @ToddGinsberg isNullOrEmpy() on Collections maybeEmptyArray<Int>()?.isNullOrEmpty() maybeEmptyMap<String, Int>()?.isNullOrEmpty() maybeEmptyCollection<String>()?.isNullOrEmpty()

  11. @ToddGinsberg Empty Collections and Maps arrayOf<Int>().ifEmpty { arrayOf(1) } listOf<Int>().ifEmpty

    { listOf(1) } setOf<Int>().ifEmpty { setOf(1) } mapOf<String,Int>().ifEmpty { mapOf("A" to 1) }
  12. @ToddGinsberg Empty Sequences val s : Sequence<Int>? = maybeEmptySequence<Int>()

  13. @ToddGinsberg Empty Sequences val s : Sequence<Int> = maybeEmptySequence<Int>() .orEmpty()

  14. @ToddGinsberg Empty Sequences val s : Sequence<Int> = maybeEmptySequence<Int>() .orEmpty()

    .ifEmpty { someDefaultSequence() }
  15. @ToddGinsberg Empty Strings val s: String = calculateAnswer() .ifEmpty {

    "Default" }
  16. @ToddGinsberg Blank Strings val s: String = calculateAnswer() .ifEmpty {

    "Default" } .ifBlank { "Default" }
  17. @ToddGinsberg Nullable Any HashCode val myHashCode: Int = myObject?.hashCode() ?:

    0
  18. @ToddGinsberg Nullable Any HashCode public inline fun Any?.hashCode(): Int =

    this?.hashCode() ?: 0 val myHashCode: Int = myObject.hashCode()
  19. @ToddGinsberg Boolean Companion fun Boolean.Companion.`¯\_(ツ)_/¯`(): Boolean = Random.nextBoolean() val majorLifeDecision

    = Boolean.`¯\_(ツ)_/¯`()
  20. @ToddGinsberg Boolean Companion @SinceKotlin("1.3") companion object {}

  21. @ToddGinsberg Basic Type Constants SIZE_BYTES and SIZE_BITS available on •

    Char • Byte • Short • Int • Long Char: 16 bits, 2 bytes Byte: 8 bits, 1 byte Short: 16 bits, 2 bytes Int: 32 bits, 4 bytes Long: 64 bits, 8 bytes
  22. @ToddGinsberg Multiplatform random() import kotlin.random.* val random = Random.nextInt(10)

  23. @ToddGinsberg Multiplatform random() public abstract class Random { public open

    fun nextInt(): Int = nextBits(32) companion object Default : Random() { // ... } }
  24. @ToddGinsberg Multiplatform random() companion object Default : Random() { private

    val defaultRandom: Random = defaultPlatformRandom() override fun nextInt(): Int = defaultRandom.nextInt() } internal expect fun defaultPlatformRandom(): Random
  25. @ToddGinsberg Multiplatform random() val winner = arrayOf(”A", ”B", ”C").random() val

    winner = listOf(”A", ”B", ”C").random() val letters = 'A' .. 'Z' val randomWord = (0..10) .map { letters.random() } .joinToString(separator = "")
  26. @ToddGinsberg Aritiy > 22 GOOD NEWS! We are no longer

    limited to 22 function arguments! val crazy = { p1: Int, p2: Int, p3: Int, p4: Int, p5: Int, p6: Int, p7: Int, p8: Int, p9: Int, p10: Int, p11: Int, p12: Int, p13: Int, p14: Int, p15: Int, p16: Int, p17: Int, p18: Int, p19: Int, p20: Int, p21: Int, p22: Int -> true }
  27. @ToddGinsberg Aritiy > 22 GOOD NEWS! We are no longer

    limited to 22 function arguments! crazy( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 )
  28. @ToddGinsberg Aritiy > 22 BAD NEWS – We are now

    limited to 254 function arguments val totallyReasonableThingToDo = { p1: Int, p2: Int, p3: Int, p4: Int, p5: Int, p6: Int, p7: Int, p8: Int, p9: Int, p10: Int, p11: Int, p12: Int, p13: Int, p14: Int, p15: Int, p16: Int, p17: Int, p18: Int, p19: Int, p20: Int, p21: Int, p22: Int, p23: Int, p24: Int, p25: Int, p26: Int, p27: Int, p28: Int, p29: Int, p30: Int, p31: Int, p32: Int, p33: Int, p34: Int, p35: Int, p36: Int, p37: Int, p38: Int, p39: Int, p40: Int, p41: Int, p42: Int, p43: Int, p44: Int, p45: Int, p46: Int, p47: Int, p48: Int, p49: Int, p50: Int, p51: Int, p52: Int, p53: Int, p54: Int, p55: Int, p56: Int, p57: Int, p58: Int, p59: Int, p60: Int, p61: Int, p62: Int, p63: Int, p64: Int, p65: Int, p66: Int, p67: Int, p68: Int, p69: Int, p70: Int, p71: Int, p72: Int, p73: Int, p74: Int, p75: Int, p76: Int, p77: Int, p78: Int, p79: Int, p80: Int, p81: Int, p82: Int, p83: Int, p84: Int, p85: Int, p86: Int, p87: Int, p88: Int, p89: Int, p90: Int, p91: Int, p92: Int, p93: Int, p94: Int, p95: Int, p96: Int, p97: Int, p98: Int, p99: Int, p100: Int, p101: Int, p102: Int, p103: Int, p104: Int, p105: Int, p106: Int, p107: Int, p108: Int, p109: Int, p110: Int, p111: Int, p112: Int, p113: Int, p114: Int, p115: Int, p116: Int, p117: Int, p118: Int, p119: Int, p120: Int, p121: Int, p122: Int, p123: Int, p124: Int, p125: Int, p126: Int, p127: Int, p128: Int, p129: Int, p130: Int, p131: Int, p132: Int, p133: Int, p134: Int, p135: Int, p136: Int, p137: Int, p138: Int, p139: Int, p140: Int, p141: Int, p142: Int, p143: Int, p144: Int, p145: Int, p146: Int, p147: Int, p148: Int, p149: Int, p150: Int, p151: Int, p152: Int, p153: Int, p154: Int, p155: Int, p156: Int, p157: Int, p158: Int, p159: Int, p160: Int, p161: Int, p162: Int, p163: Int, p164: Int, p165: Int, p166: Int, p167: Int, p168: Int, p169: Int, p170: Int, p171: Int, p172: Int, p173: Int, p174: Int, p175: Int, p176: Int, p177: Int, p178: Int, p179: Int, p180: Int, p181: Int, p182: Int, p183: Int, p184: Int, p185: Int, p186: Int, p187: Int, p188: Int, p189: Int, p190: Int, p191: Int, p192: Int, p193: Int, p194: Int, p195: Int, p196: Int, p197: Int, p198: Int, p199: Int, p200: Int, p201: Int, p202: Int, p203: Int, p204: Int, p205: Int, p206: Int, p207: Int, p208: Int, p209: Int, p210: Int, p211: Int, p212: Int, p213: Int, p214: Int, p215: Int, p216: Int, p217: Int, p218: Int, p219: Int, p220: Int, p221: Int, p222: Int, p223: Int, p224: Int, p225: Int, p226: Int, p227: Int, p228: Int, p229: Int, p230: Int, p231: Int, p232: Int, p233: Int, p234: Int, p235: Int, p236: Int, p237: Int, p238: Int, p239: Int, p240: Int, p241: Int, p242: Int, p243: Int, p244: Int, p245: Int, p246: Int, p247: Int, p248: Int, p249: Int, p250: Int, p251: Int, p252: Int, p253: Int, p254: Int -> true }
  29. @ToddGinsberg Aritiy > 22 BAD NEWS – We are now

    limited to 254 function arguments totallyReasonableThingToDo( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 200, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254 )
  30. @ToddGinsberg Aritiy > 22 /** A function that takes 0

    arguments. */ public interface Function0<out R> : Function<R> { public operator fun invoke(): R }
  31. @ToddGinsberg Aritiy > 22 /** A function that takes 1

    argument. */ public interface Function1<in P1, out R> : Function<R> { public operator fun invoke(p1: P1): R }
  32. @ToddGinsberg Aritiy > 22 interface FunctionN<out R> : Function<R> {

    operator fun invoke(vararg args: Any?): R override val arity: Int }
  33. @ToddGinsberg Sealed Class Reflection sealed class Expr data class Const(val

    number: Double) : Expr() data class Sum(val e1: Expr, val e2: Expr) : Expr() object NotANumber : Expr() println(Expr::class .sealedSubclasses .map { it.simpleName } ) // [Const, Sum, NotANumber]
  34. @ToddGinsberg Nested Declarations in Annotations annotation class AsyncWork( val threads:

    Int = maxThreads ) { companion object { const val maxThreads: Int = 8 } }
  35. @ToddGinsberg Nested Declarations in Annotations annotation class Transaction( val isolation:

    Isolation ) { enum class Isolation { CREATE_NEW, REUSE_EXISTING, NONE } } @Transaction(Transaction.Isolation.CREATE_NEW) class Example
  36. @ToddGinsberg Nested Declarations in Annotations annotation class Settings { annotation

    class Name(val name: String) annotation class PasswordStrategy( val minChars: Int, val minComplexity: Double = 1.0 ) } @Settings.Name("Some kind of provider") @Settings.PasswordStrategy(minChars = 10) class Provider
  37. @ToddGinsberg Progressive Mode • Compiler Arguments: • -progressive • -Xprogressive

    • Trade-offs: • Bug fixes now • Possibly broken code
  38. @ToddGinsberg Compiler Arguments • Compiler Arguments in a File •

    Existing: -Xargfile=filename.txt • New: @filename.txt
  39. @ToddGinsberg Graduated

  40. @ToddGinsberg Start at the Beginning… suspend fun main(args: Array<String>) {

    }
  41. @ToddGinsberg Start at the Beginning… suspend fun main() { }

  42. @ToddGinsberg Coroutines! suspend fun doSomeWork(): Int { val a1 =

    async { doSomeLongRunningWork(42) } val a2 = async { doSomeLongRunningWork(806) } return a1.await() + a2.await() }
  43. @ToddGinsberg Coroutines! suspend fun doSomeWork(): Int { val a1 =

    async { doSomeLongRunningWork(42) } val a2 = async { doSomeLongRunningWork(806) } return a1.await() + a2.await() }
  44. @ToddGinsberg Structured Concurrency suspend fun doSomeWork(): Int = coroutineScope {

    val a1 = async { doSomeLongRunningWork(42) } val a2 = async { doSomeLongRunningWork(806) } a1.await() + a2.await() }
  45. @ToddGinsberg Structured Concurrency GlobalScope.launch { doSomeWork() }

  46. @ToddGinsberg Changes to Lazy Sequences fun lazyFib(): Sequence<Int> = buildSequence

    { var state = Pair(0, 1) while(true) { yield(state.second) state = Pair( state.second, state.first + state.second ) } }
  47. @ToddGinsberg Changes to Lazy Sequences fun lazyFib(): Sequence<Int> = sequence

    { var state = Pair(0, 1) while(true) { yield(state.second) state = Pair( state.second, state.first + state.second ) } }
  48. @ToddGinsberg Experimental

  49. @ToddGinsberg Inline Classes fun canVote(years: Int): Boolean = years >=

    18 inline class Age(val years: Int) fun canVote(age: Age): Boolean = age.years >= 18
  50. @ToddGinsberg Inline Classes inline class Age(val years: Int) { fun

    minor(): Boolean = years < 18 } fun canVote(age: Age): Boolean = !age.minor()
  51. @ToddGinsberg Inline Classes • Must have a public constructor with

    a single val • No init block • Must be final • Cannot extend anything • Cannot have any additional properties • Must be a top level class • Cannot have inner classes • Cannot be defined with recursively defined generics Limitations!
  52. @ToddGinsberg Unsigned Types val aUInt: UInt = 42u val aULong:

    ULong = 42uL
  53. @ToddGinsberg Unsigned Types val myUByte: UByte = someByte.toUByte() val myUShort:

    UShort = someShort.toUShort() val myUInt: UInt = someInt.toUInt() val myULong: ULong = someLong.toULong()
  54. @ToddGinsberg Unsigned Types val uByte: UByte = "255".toUByte() val uShort:

    UShort = "65535".toUShort() val uInt: UInt = "4294967295".toUInt() val uLong: ULong = "18446744073709551615".toULong()
  55. @ToddGinsberg Unsigned Types As well as… • Hex Literals =

    0xFFFF_FFFFu • Unsigned Arrays = uintArrayOf(1u, 2u, 3u) • Unsigned Ranges = (0u .. UInt.MAX_VALUE) • Remove warnings with @ExperimentalUnsignedTypes
  56. @ToddGinsberg Contracts fun CharSequence?.isNullOrBlank() : Boolean = this == null

    || this.isBlank() val s: String? = calculateString() if(!s.isNullOrBlank()) { s?.reversed() }
  57. @ToddGinsberg Contracts @ExperimentalContracts fun CharSequence?.isNullOrBlank() : Boolean { contract {

    returns (false) implies (this@isNullOrBlank != null) } return this == null || this.isBlank() }
  58. @ToddGinsberg Contracts @ExperimentalContracts fun main(args: Array<String>) { val s: String?

    = calculateString() if(!s.isNullOrBlank()) { s.reversed() } }
  59. @ToddGinsberg Contracts fun main(args: Array<String>) { val myValue: String run

    { myValue = "Hello, World!” } }
  60. @ToddGinsberg Contracts @ExperimentalContracts inline fun <R> run(block: () -> R):

    R { contract { callsInPlace( block, InvocationKind.EXACTLY_ONCE ) } return block() }
  61. @ToddGinsberg Experimental Annotations @Experimental(level = Experimental.Level.WARNING) annotation class MyExperimentalApi @MyExperimentalApi

    class SomeExperimentalThing { // ... }
  62. @ToddGinsberg Experimental Annotations @MyExperimentalApi fun doSomething(n: SomeExperimentalThing) { // ...

    } @UseExperimental(MyExperimentalApi::class) fun doSomethingElse() { SomeExperimentalThing().doSomething() }
  63. @ToddGinsberg More Details https://todd.ginsberg.com/post/kotlin-1.3-features/

  64. Than You! @ToddGinsberg https://todd.ginsberg.com todd@ginsberg.com