Kotlin

Impressions and conclusions

after year on production

Contens

  • Why Kotlin?
  • Few Examples
  • Classes and properties
  • Typing in Kotlin
  • Functions and Lambdas
  • Extension Functions
  • Conclusions

Things I won't tell You about

  • Functional programming in Kotlin
  • What the hell are Delegates?
  • DSL in Kotlin

I wanted, but they deserve for a separate presentation

Why Kotlin?

Java is dead

Java is slowly collapsing giant

Text

Text

Text

Text

Google Search and Book Selling is indicator of what people are interested in

Why Kotlin?

There is so much mature JVM programming languages

Why Kotlin?

Both Scala and Groovy limp on:

  • Compilation time
  • Execution time
  • Java compability

They are fun, but not pragmatic

Java compatibility

Cmd + Shift + A

Ctrl + Shift + A

Configure Kotlin in the project

Cmd + Shift + A

Ctrl + Shift + A

Convert Java File to Kotlin File

Kotlin

Kotlin have most of the modern languages features (and some custom), while keeping build and execution time close Java.

Few examples

Hello World

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

Iteration

for (i in 1..10) {
   print(i)
}
// 12345678910
for (i in 10 downTo 1 step 2) {
   print(i)
}
// 108642
for (c in 'A'..'Z') {
   print(c)
}
// ABCDEFGHIJKLMNOPQRSTUVWXYZ
for (c in "Some text") {
   print("$c.")
}
// S.o.m.e. .t.e.x.t.

Iteration

val capitolToCountry = listOf(
    "Washington" to "United States of America", 
    "Warsaw" to "Poland", 
    "London" to "Great Britan"
)


for ((capitol, country) in capitolToCountry) {
    println("Capitol of $country is $capitol")
}

// Capitol of United States of America is Washington
// Capitol of Poland is Warsaw
// Capitol of Great Britan is London

Iteration

listOf(User("Marcin", "Moskala"), User("Michal", "Michalski"), User("Ania", "Mania"))
        .filter { it.name.startsWith("M") }
        .map { (name, surname) -> "$name $surname" }
        .joinToString(separator = " and ")
        .let(::print)

Iteration

val s = (1..10) // Range from 1 to 10
            .filter { it % 2 == 0 } // [2, 4, 6, ...]
            .map { it * it } // [4, 16, 36, ...]
            .sum() // 220

Quick Sort

fun <T : Comparable<T>> List<T>.quickSort(): List<T> {
    if (size < 2) return this
    val pivot = first()
    val (smaller, greater) = subList(1, size).partition { it <= pivot }
    return smaller.quickSort() + pivot + greater.quickSort()
}

Conclusions

Short

Good-looking

Minimal syntax

Lot's of possibilities

Null safety &

Read-only

Safeness

Language safeness - more errors can be prevented by checks at compile time instead of falling at run time. Also language is referred as safe when it is promoting way of coding that is know as more secure.

Read-only properties

val name: String = "Marcin"

Read only

var name: String = "Marcin"

Changeable

Null safety

var person: Person

Must be inilialized

var person: Person = null

Not null type cannot be null

var person: Person? = null

? after type makes it nullable

person.name

Nullable must be unpacked

Null safety

person?.name

Safe call (null if person is null)

person!!.name

Unsafe call (exception if person is null)

if(person != null) {
    person.name
}

Smart Cast (after nullability check, object is casted to not-null)

if(person == null)
    return

person.name
if(person != null && person.name == "Marcin")
if(person == null || person.surname == "Bąk")

Elvis operator

person?.name ?: "unknown"
val name = person?.name ?: throw Error("No person or name is null")
val name = person?.name ?: return

Conclusion

Null safety prevents from NPE - most common Java error.

Null safety makes Kotlin code much safer while it cost nearly nothing. It is Simple and smart.

One catch - when we assume that some value form API or Java lib is not-null and we will have case where it is then we have an exception even if we don't use it.

 

Null safety promotes val usage over var, because in val there is no Smart Casting in case of multithreading.

Kotlin often promotes using val over var. It is good for thread safety and also really good practice.

Classes and properties

Classes

// Java
public class PersonJava {
   private String name;
   private String surname;
   private int age;

   PersonJava(String name, String surname, int age) {
       this.setName(name);
       this.setSurname(surname);
       this.setAge(age);
   }

   public String getName() {
       return name;
   }

   public void setName(String name) {
       this.name = name;
   }

   public String getSurname() {
       return surname;
   }

   public void setSurname(String surname) {
       this.surname = surname;
   }

   public int getAge() {
       return age;
   }

   public void setAge(int age) {
       this.age = age;
   }
}

Classes

class Person {
    var name: String
    var surname: String
    var age: Int

    constructor(name: String, surname: String, age: Int) {
        this.name = name
        this.surname = surname
        this.age = age
    }
}

Yap, this is exactly the same

Getters and setters are there

Classes

class Person(name: String, surname: String, age: Int) {
    var name: String = name
    var surname: String = surname
    var age: Int = age
}

Still the same

Primary constructor

Classes

class Person(val name: String, val surname: String, val age: Int)

Yap, this is exactly the same

Getters and setters are there

Properties

var name: String? = null
    get() = name?.capitalize()
    set(value) {
        if(value == null || value.length == 0) return
        field = value
    }

We can still edit getters and setters

Kotlin property = Java private field + accessors

accessors = getter for var, getter + setter for var

Properties

class Person(val name: String, val surname: String) {
    val fullName: String
        get() = "$name $surname"
}

Here Kotlin property is just a setter

Conclusion

Kotlin syntax for defining classes is zero-boilerplate.

Kotlin properties are much more powerful then Java fields.

This leads to short, elegant and easily changeable code.

Typeing in Kotlin

Type system

val name = "Marcin"
val name: String = "Marcin"
listOf(1, 2, 3, 4, 5, 6).filter { it > 3 }.map { it * 2 }.sum()
val double: (Int)->Int = { i -> i * 2 }
val double = { i: Int -> i * 2 }

Smart Casting

Conclusion

Having static typing and good inference system, we can achieve  all benefits from static typing while getting most of benefits form dynamic.

Functions

Functions

Single-expression function

Type is inferred

Functions everywhere

fun double(i: Int) = i * 2

class A() {

    fun triple(i: Int) = i * 3

    fun twelveTimes(i: Int): Int {
        fun fourTimes(i: Int) = double(double(i))
        return triple(fourTimes(i))
    }
}


fun main(args: Array<String>) {
    double(1) // 2
    A().twelveTimes(2) // 24
}

Top-level function

Mamber function

Local function

Lambdas (closures in fact)

fun main(args: Array<String>) {
    var a: Int = 0
    val inc = { a++ }
    val dec = { a--}
    val prt = { println(a) }
    button1.onClick = { inc(); prt() }
    button2.onClick = { dec(); prt() }
}

Lambdas (closures in fact)

fun main(args: Array<String>) {
    var a: Int = 0
    button1.onClick = { print(a++) }
    button2.onClick = { print(a--) }
}

Higher order functions

fun getCounter(): ()->Int {
    var i: Int = 0
    return { i++ }
}

Java SAM to Kotlin function

// Java
interface OnClickListener {
    fun onClick(v: View)
}
// Java
View.OnClickListener listener = new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // Code
    }
};
val listener = View.OnClickListener { /* Code */ }

Java SAM parameter to Kotlin function parameter

// Java
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Toast.makeText(getBaseContext(), "Button clicked", Toast.LENGTH_LONG).show();
    }
});
button.setOnClickListener { toast("Button clicked") }

Conclusion

Kotlin allows fully functional programming.

It's function syntax it short and simple.

Kotlin lambdas not only shorter, but also much more powerful then Java anonymous objects or Java 8 lambdas.

Kotlin made a bridge to simply use Java methods with function interfaces.

Whole function system makes Kotlin syntax shorter and more readable. It also prevents from redundancy.

Extension

functions

Java Utils hell

Java Utils hell

StringUtils.capitalize(str)
val replacedStr = StringUtils.replaceAll(str, "name" to name, "surname" to surname)
val capitalizedStr = StringUtils.capitalize(replacedStr)

Kotlin extension functions

str.capitalize()
str.replaceAll("{name}" to name, "{surname}" to surname)
    .capitalize()

Kotlin extension functions

fun String.noLongerThen(max: Int): String {
    return this.substring(0, Math.min(max, this.length))
}

fun main(args: Array<String>) {
    println("Joe".noLongerThen(4)) // Joe
    println("James".noLongerThen(4)) // Jame
    println("Ashley".noLongerThen(4)) // Ashl
}

Kotlin extension functions

Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
fun Context.toast(text: String) {
    Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
}
toast(text)

Kotlin extension functions

in practice

view.visibility = Visible.GONE
ViewUtlis.hide(view)

We often do

No better

view.hide()
ViewUtlis.hide(view)

Better

Good looking

Less redundant

Simple

Kotlin extension properties

val Context.appVersion: String
    get() = packageManager.getPackageInfo(packageName, 0).versionName
var View.isVisible: Boolean
    get() = visibility == View.VISIBLE
    set(value) {
        visibility = if (value) View.VISIBLE else View.GONE
    }

Conclusion

Kotlin Extension Functions lead to good looking, less redundant and simple code.

They allow to extend libraries with own functionalities.

It is dangerous - each project have it's own extension functions, so it is leading to different programming style.

Final conclusions

Philosophy of Kotlin

  • Pragmatic
  • Concise

  • Safe

  • Interoperable

Pragmatic

Kotlin is a practical language designed to solve real-world problems. 

Kotlin is based on years of industry experience.

Kotlin is shifting lot's of responsibilities from programmer to IDE.

Concise

  • Zero boilerplate
  • Lot's of ways to omit redundancy
  • Promotes making reusable code
  • Even Java functions are shorted

Kotlin syntax is minimal

  • Minimizes redundancy
  • Allow funcion programming

Kotlin syntax is easily changeable

Safe

  • Null safety
  • Statically typed while smart casted
  • Promotes read only values
  • Promotes immutable types

Kotlin syntax is safe

Interoperable

Kotlin is perfectly working with Java APIs, tools and libraries. Also Kotlin can be always used from Java. It is keeping all that Java gives, while adding it's own features.

Kotlin

By Marcin Moskala

Kotlin

  • 664