Kotlin 1.3

What's new?

Kittinun Vantasin

About me

Mobile Enthusiastic 📱🍭

💖 Kotlin + Open source

Works at Merpay in Tokyo 🗼

github.com/kittinunf

@kittinunf

About me

from wonderful land of smiles ☺️

loves thai food because it is yummy 😋

rides Tuktuk while in Bangkok 💨

Kotlin 1.3

2010  Started

2011  Revealed

Late 2012  OSS

2014 

Gain popularity

2016

Hit 1.0

2017

Hit 1.1

Late 2017

Hit 1.2

2018

Hit 1.3

What's new?

Contracts

Capture variable in local when scope

@JvmStatic & @JvmField in interfaces

fun main()

255 arity function

inline classes! + USignedTypes

consistent empty related functions

etc.

Guide

  
  Kotlin 1.2.71 or earlier
  
  Awesome Kotlin 1.3

Contracts

  
  fun foo(s: String?) {
    s?.let {
      s.length // smart cast is here
    }
    
    if (s.isNotNull()) {
      s?.length // no smart cast here :(
    }
  }

  fun String?.isNotNull() = this != null
  
  fun foo(s: String?) {
    s?.let {
      s.length // smart cast here
    }

    if (isNotNull(s)) {
      s.length // also smart cast here
    }
  }

  fun isNotNull(value: Any?): Boolean {
    contract { returns(true) implies (value != null) }
    return value != null
  }

Contracts cont.

  
  
  val myValue: String
  
  myRun {
    myValue = "Hello, World!"   // Error here ... :(
  }
  
  fun <R> myRun(block: () -> R): R {
    return block()
  }
  
  
  val myValue: String
  
  myRun {
    myValue = "Hello, World!"   // Woohoo it works!
  }
  
  fun <R> myRun(block: () -> R): R {
    contract {
      callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
  }

Capture when scope

  
  val answer = calculate()
  
  return when(answer) {
    42 -> "Right answer!"
    123 -> "ARGHHHHH!"
    else -> "Sorry, $answer is not correct"
  }

  answer // I don't want to see you here

  
  

  return when(val answer = calculate()) {
    42 -> "Right answer!"
    123 -> "ARGHHHHH!"
    else -> "Sorry, $answer is not correct"
  }


  //answer you are not being seen here

@JvmStatic & @JvmField 

  
interface Foo {
    
  companion object {
        
    @JvmField
    val bar: Int = 42
        
    @JvmStatic
    fun sayHello(name: String = "") {
      println("Hello, $name")
    }
  }
}
  

fun main() 

  
  fun main() {
    println("Hello, world")
  }


  // compare to the full-blown version

  fun main(args : Array<String>) { 
    println("Hello, world") 
  }

  

255 Arity function 

  
  
  fun onlyRealManCanUnderstandThis(
     block: (Any, Any, Any, /* 250 more */, Any, Any
  ) {
    block(Any(), Any(), /* 250 more */, Any(), Any())
  }
  
  
  @SinceKotlin("1.3")
  interface FunctionN<out R> : Function<R> {
    operator fun invoke(vararg args: Any?): R
    
    override val arity: Int
  }

Inline classes!!

  
  
  class FirstNameInKana(n: String) 
  class LastNameInKana(n: String)

  fun formattedName(f: FirstName, l: LastName) {
    println("$l $f")
  }

  formattedName(
    FirstNameInKana("やまだ"), 
    LastNameInKana("たろう")
  )

  typealias FirstName = String // OK, but meh :|
  typealias LastName = String // OK, but meh :|
  

  inline class FirstNameInKana(n: String) 
  inline class LastNameInKana(n: String)

  fun formattedName(f: FirstName, l: LastName) {
    println("$l $f")
  }

  formattedName(
    FirstNameInKana("やまだ"), 
    LastNameInKana("たろう")
  )
  
  

  
  

Inline classes cont.

Must have a public constructor with a single val

No init block

Must be final

Cannot extend anything - implement interfaces OK

Cannot have any additional properties

Must be a top level class

HANDLE WITH CARE

UTypes FTW

  
  
  // Literal shortcode for UInt
  val aUInt: UInt = 3u
  val aULong: ULong = 3uL

  // And from Hex...
  val hexUByte: UByte = 0xFFu  // 255
  val hexUShort: UShort = 0xFFFFu  // 65535
  val hexUInt: UInt = 0xFFFF_FFFFu  // 4294967295
  val hexULong: ULong = 0xFFFF_FFFF_FFFF_FFFFu  // xD

Empty related func.

  
  
  fun calculateArray(): Array<Int>? {
    // some calculation

    
  }

  val array = calculateArray()

  array.isNullOrEmpty() // ERRRAARGGHHH, there is none
  
  
  fun calculateArray(): Array<Int>? {
    // heavy calculation

    
  }

  val array = calculateArray()

  if (array.isNullOrEmpty()) {
    // :) Joy
  }
  
  
  val maybeArray: Array<T>
  maybeArray.isNullOrEmpty()


  val maybeCollection: Collection<T>
  maybeCollection.isNullOrEmpty()


  val maybeMap: Map<T, U>
  maybeMap.isNullOrEmpty()
  
  
  

Empty related func.

  
  
  val listOfFeatures: List<String> = ...
  println(listOfFeatures.ifEmpty { 
     listOf("Default1", "Default2") 
  })

  
  val townProvidedByUser: String = ...
  println(townProvidedByUser.ifBlank { "東京" })

Serialization Library

  
  @Serializable
  data class Destination(
        val name: String? = "",
        val country : String? = "",
        val code : Int = 0,
        @Optional
        val isMetro : Boolean = false,
        @Transient
        val favorite : Boolean = false
  )
  
  val tokyoAsString = JSON.stringify(
    Destination(name = "東京", country = "Japan") 
  ) // { "name":"東京","country":"Japan","code":0 }
  

  val tokyo = JSON.unquoted.parse<Destination>(
    "{ name:東京,country:Japan, code:12 }"
  ) // Destination(name = "東京", country = "Japan", code = 12)

Caveats

The experimental feature is really experimenting!

They can be breaking for the next version! :)

How do you feel about 1.3?

Q & A

Made with Slides.com