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

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.

Todd Ginsberg

November 20, 2018
Tweet

More Decks by Todd Ginsberg

Other Decks in Technology

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 Capture the Subject of When val answer = theAnswer()

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

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

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

    nameAndLength: Map<String, Int> = people.associateWith { it.length }
  7. @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) }
  8. @ToddGinsberg Nullable Any HashCode public inline fun Any?.hashCode(): Int =

    this?.hashCode() ?: 0 val myHashCode: Int = myObject.hashCode()
  9. @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
  10. @ToddGinsberg Multiplatform random() public abstract class Random { public open

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

    val defaultRandom: Random = defaultPlatformRandom() override fun nextInt(): Int = defaultRandom.nextInt() } internal expect fun defaultPlatformRandom(): Random
  12. @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 = "")
  13. @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 }
  14. @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 )
  15. @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 }
  16. @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 )
  17. @ToddGinsberg Aritiy > 22 /** A function that takes 0

    arguments. */ public interface Function0<out R> : Function<R> { public operator fun invoke(): R }
  18. @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 }
  19. @ToddGinsberg Aritiy > 22 interface FunctionN<out R> : Function<R> {

    operator fun invoke(vararg args: Any?): R override val arity: Int }
  20. @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]
  21. @ToddGinsberg Nested Declarations in Annotations annotation class AsyncWork( val threads:

    Int = maxThreads ) { companion object { const val maxThreads: Int = 8 } }
  22. @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
  23. @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
  24. @ToddGinsberg Progressive Mode • Compiler Arguments: • -progressive • -Xprogressive

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

    Existing: -Xargfile=filename.txt • New: @filename.txt
  26. @ToddGinsberg Coroutines! suspend fun doSomeWork(): Int { val a1 =

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

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

    val a1 = async { doSomeLongRunningWork(42) } val a2 = async { doSomeLongRunningWork(806) } a1.await() + a2.await() }
  29. @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 ) } }
  30. @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 ) } }
  31. @ToddGinsberg Inline Classes fun canVote(years: Int): Boolean = years >=

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

    minor(): Boolean = years < 18 } fun canVote(age: Age): Boolean = !age.minor()
  33. @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!
  34. @ToddGinsberg Unsigned Types val myUByte: UByte = someByte.toUByte() val myUShort:

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

    UShort = "65535".toUShort() val uInt: UInt = "4294967295".toUInt() val uLong: ULong = "18446744073709551615".toULong()
  36. @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
  37. @ToddGinsberg Contracts fun CharSequence?.isNullOrBlank() : Boolean = this == null

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

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

    = calculateString() if(!s.isNullOrBlank()) { s.reversed() } }
  40. @ToddGinsberg Contracts @ExperimentalContracts inline fun <R> run(block: () -> R):

    R { contract { callsInPlace( block, InvocationKind.EXACTLY_ONCE ) } return block() }
  41. @ToddGinsberg Experimental Annotations @MyExperimentalApi fun doSomething(n: SomeExperimentalThing) { // ...

    } @UseExperimental(MyExperimentalApi::class) fun doSomethingElse() { SomeExperimentalThing().doSomething() }