Kotlin Lunch and Learn

Ce0de7299bfbc54dd950689e04a4f053?s=47 Cody Engel
September 21, 2018

Kotlin Lunch and Learn

This was a lunch and learn I gave about Kotlin at ActiveCampaign.

Ce0de7299bfbc54dd950689e04a4f053?s=128

Cody Engel

September 21, 2018
Tweet

Transcript

  1. Kotlin, What Is It? ! Cody Engel

  2. Cody Engel NIU Computer Science Alum

  3. Blogging, It’s A Helluva Drug (Also got into programming through

    editing Wordpress themes)
  4. Android 2.2 Started Android Development when this was the dominant

    version.
  5. Started Learning Kotlin End of 2016

  6. Convinced Team to Use Kotlin in 2017

  7. Joined a Kotlin-only Android Team 2018

  8. All aboard the Kotlin hype-train. BreadLord

  9. Kotlin, A Brief History

  10. –Dmitry Jemerov, August 2, 2011 “We (JetBrains) want to become

    more productive by switching to a more expressive language.”
  11. Kotlin Named after the Russian island, Kotlin.

  12. Java Named after the Indonesian island of Java.

  13. Kotlin v1.0 released on February 15, 2016.

  14. Cody decides to start learning Kotlin in December 2016.

  15. Google I/O 2017 Kotlin officially supported by Google for Android

    development.
  16. Kotlin v1.2 released on November 28, 2017. Multiplatform Projects pick

    up steam.
  17. Kotlin 1.3 Coroutines will graduate from experimental to stable.

  18. Kotlin Basics (Less is More)

  19. Functions

  20. fun sum(a: Int, b: Int): Int { return a +

    b } Functions
  21. fun sum(a: Int, b: Int) = a + b Functions

  22. fun printSum(a: Int, b: Int): Unit { println("sum of $a

    and $b is ${a + b}") } Functions
  23. fun printSum(a: Int, b: Int) { println("sum of $a and

    $b is ${a + b}") } Functions
  24. Variables

  25. val immutableNumber: Int = 1 Variables

  26. val immutableNumber = 1 Variables

  27. var mutableNumber = 5 mutableNumber = 54 Variables

  28. String Templates

  29. var a = 1 val s1 = "a is $a"

    // a is 1 String Templates
  30. a = 2 val s2 = "${s1.replace("is", "was")}, but now

    is $a” // a was 1 but now is 2 String Templates
  31. Conditional Expressions

  32. fun maxOf(a: Int, b: Int): Int { if (a >

    b) { return a } else { return b } } Conditional Expressions
  33. fun maxOf(a: Int, b: Int) = if (a > b)

    a else b Conditional Expressions
  34. Handling Null

  35. val maybeNull: String? = null val notNull: String = if

    (maybeNull != null) maybeNull else "" Handling Null
  36. val maybeNull: String? = null val notNull: String = maybeNull

    ?: "" Handling Null
  37. val maybeNull: String? = null val length: Int = maybeNull?.length

    ?: 0 Handling Null
  38. val listWithNulls: List<String?> = listOf("Kotlin", null) for (item in listWithNulls)

    { item?.let { println(it) } //prints Kotlin and ignores null } Handling Null
  39. Type Casting

  40. if (x instanceof Integer) { System.out.print((Integer) x + 1); }

    else if (x instanceof String) { System.out.print(((String) x).length() + 1); } else if (x instanceof List<Integer>) { Integer total = 0; for (Integer i : (List<Integer>) x) { total += i; } System.out.print(total); } Type Casting
  41. if (x is Int) { print(x + 1) } else

    if (x is String) { print(x.length + 1) } else if (x is IntArray) { print(x.sum()) } Type Casting
  42. when (x) { is Int -> print(x + 1) is

    String -> print(x.length + 1) is IntArray -> print(x.sum()) } Type Casting
  43. Classes in Kotlin (Easier to Represent Data)

  44. –KotlinLang.org - Data Classes Documentation “We frequently create classes whose

    main purpose is to hold data. In such a class some standard functionality and utility functions are often mechanically derivable from the data. In Kotlin, this is called a data class.”
  45. public class Person { private final String name; private final

    int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } } Data Classes
  46. public class Person { private final String name; private final

    int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } // but wait… there’s more! @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Person person = (Person) o; return age == person.age && Objects.equals(name, person.name); } @Override public int hashCode() { return Objects.hash(name, age); } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } } Data Classes
  47. data class Person(val name: String, val age: Int) Data Classes

  48. val person = Person("Cody", "56") person.age person.name person.equals(anotherPerson) person.hashCode() person.toString()

    person.copy(name = "Bob") (name, age) = person Data Classes
  49. –KotlinLang.org - Sealed Classes Documentation “Sealed classes are used for

    representing restricted class hierarchies, when a value can have one of the types from a limited set, but cannot have any other type. They are, in a sense, an extension of enum classes: the set of values for an enum type is also restricted, but each enum constant exists only as a single instance, whereas a subclass of a sealed class can have multiple instances which can contain state.”
  50. –Cody Engel - Kotlin Lunch & Learn “Sealed classes are

    used for representing restricted class hierarchies. They are similar to enums, except they can have multiple instances of the same type.”
  51. sealed class Expr data class Const(val number: Double) : Expr()

    data class Sum(val firstNum: Expr, val secondNum: Expr) : Expr() object NotANumber : Expr() Sealed Classes
  52. fun eval(expr: Expr): Double = when(expr) { is Const ->

    expr.number is Sum -> eval(expr.firstNum) + eval(expr.secondNum) NotANumber -> Double.NaN // an `else` clause is not required because we've covered all the cases } Sealed Classes
  53. Default Values

  54. class ImageCache( val timeRetrieved: Long, val wasSuccessful: Boolean, val cacheExpirationMs:

    Long = 300000 ) Default Values
  55. class ImageCache( val timeRetrieved: Long, val wasSuccessful: Boolean, val cacheExpirationMs:

    Long = 300000 ) val imageCache = ImageCache( timeRetrieved = 40, wasSuccessful = false ) val imageCache = ImageCache( timeRetrieved = 40, wasSuccessful = false, cacheExpirationMs = 5000 ) Default Values
  56. Extensions (Less Utils and Better Null Safety)

  57. Totally Fictitious API Response { "p_admin": "1", "pg_list_add": "1", "pg_list_edit":

    “0", "pg_list_delete": "1", "pg_list_headers": "0", "pg_list_emailaccount": "1", "pg_list_bounce": "1", "pg_message_add": "1", "pg_message_edit": null, "pg_message_delete": "0" }
  58. Extension Property

  59. val String.asBoolean: Boolean get() = this != “0" //… val

    pAdmin: String = "1" pAdmin.asBoolean Extension Property
  60. val String?.asBoolean: Boolean get() = this != null && this

    != "0" //… val pAdmin: String? = null pAdmin.asBoolean Extension Property
  61. Extension Function

  62. fun <T> MutableList<T>.swap(index1: Int, index2: Int) { val tmp =

    this[index1] this[index1] = this[index2] this[index2] = tmp } //… val myList = mutableListOf<Int>(55, 32, 45) myList.swap(0, 2) Extension Function
  63. Delegation (Composition Over Inheritance)

  64. Property Delegation

  65. private ExpensiveObjectToCreate _expensiveObject = null; ExpensiveObjectToCreate getExpensiveObject() { if (_expensiveObject

    == null) { _expensiveObject = new ExpensiveObjectToCreate(); } return _expensiveObject; } Property Delegation
  66. val expensiveObject by lazy { ExpensiveObjectToCreate() } Property Delegation

  67. private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? =

    null) : Lazy<T>, Serializable { private var initializer: (() -> T)? = initializer @Volatile private var _value: Any? = UNINITIALIZED_VALUE // final field is required to enable safe publication of constructed instance private val lock = lock ?: this override val value: T get() { val _v1 = _value if (_v1 !== UNINITIALIZED_VALUE) { @Suppress("UNCHECKED_CAST") return _v1 as T } return synchronized(lock) { val _v2 = _value if (_v2 !== UNINITIALIZED_VALUE) { @Suppress("UNCHECKED_CAST") (_v2 as T) } else { val typedValue = initializer!!() _value = typedValue initializer = null typedValue } } } override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet." private fun writeReplace(): Any = InitializedLazyImpl(value) } Property Delegation
  68. Cody’s Animal App …Or the best example he could think

    of for class delegation.
  69. interface Communicate { fun communicate() } class CatCommunicator() : Communicate

    { override fun communicate() { println("Meow") } } class DogCommunicator() : Communicate { override fun communicate() { println("Woof") } } class Animal(communicate: Communicate) : Communicate by communicate fun main(args: Array<String>) { val catCommunicator = CatCommunicator() val dogCommunicator = DogCommunicator() Animal(catCommunicator).communicate() // Meow Animal(dogCommunicator).communicate() // Woof } Class Delegation
  70. interface Communicate { fun communicate() } class CatCommunicator() : Communicate

    { override fun communicate() { println("Meow") } } class DogCommunicator() : Communicate { override fun communicate() { println("Woof") } } class Animal(communicate: Communicate) : Communicate by communicate fun main(args: Array<String>) { val catCommunicator = CatCommunicator() val dogCommunicator = DogCommunicator() Animal(catCommunicator).communicate() // Meow Animal(dogCommunicator).communicate() // Woof } Class Delegation
  71. interface Communicate { fun communicate() } class CatCommunicator() : Communicate

    { override fun communicate() { println("Meow") } } class DogCommunicator() : Communicate { override fun communicate() { println("Woof") } } class Animal(communicate: Communicate) : Communicate by communicate fun main(args: Array<String>) { val catCommunicator = CatCommunicator() val dogCommunicator = DogCommunicator() Animal(catCommunicator).communicate() // Meow Animal(dogCommunicator).communicate() // Woof } Class Delegation
  72. interface Communicate { fun communicate() } class CatCommunicator() : Communicate

    { override fun communicate() { println("Meow") } } class DogCommunicator() : Communicate { override fun communicate() { println("Woof") } } class Animal(communicate: Communicate) : Communicate by communicate fun main(args: Array<String>) { val catCommunicator = CatCommunicator() val dogCommunicator = DogCommunicator() Animal(catCommunicator).communicate() // Meow Animal(dogCommunicator).communicate() // Woof } Class Delegation
  73. interface Communicate { fun communicate() } class CatCommunicator() : Communicate

    { override fun communicate() { println("Meow") } } class DogCommunicator() : Communicate { override fun communicate() { println("Woof") } } class Animal(communicate: Communicate) : Communicate by communicate fun main(args: Array<String>) { val catCommunicator = CatCommunicator() val dogCommunicator = DogCommunicator() Animal(catCommunicator).communicate() // Meow Animal(dogCommunicator).communicate() // Woof } Class Delegation
  74. interface Communicate { fun communicate() } class CatCommunicator() : Communicate

    { override fun communicate() { println("Meow") } } class DogCommunicator() : Communicate { override fun communicate() { println("Woof") } } class Animal(communicate: Communicate) : Communicate by communicate fun main(args: Array<String>) { val catCommunicator = CatCommunicator() val dogCommunicator = DogCommunicator() Animal(catCommunicator).communicate() // Meow Animal(dogCommunicator).communicate() // Woof } Class Delegation
  75. Higher Order Functions (Because Functional is Quite Functional)

  76. –Wikipedia “In mathematics and computer science, a higher-order function (also

    functional, functional form or functor) is a function that does at least one of the following: takes one or more functions as arguments (i.e. procedural parameters), returns a function as its result.”
  77. Sandwich Code

  78. Sandwich Code

  79. val start = System.currentTimeMillis() BreadLord.whatShouldMobileWorkOnThisWeek() val executionTime = System.currentTimeMillis() -

    start Sandwich Code
  80. val executionTime = measureTimeMillis { BreadLord.whatShouldMobileWorkOnThisWeek() } Sandwich Code

  81. public fun measureTimeMillis(block: () -> Unit) : Long { val

    start = System.currentTimeMillis() block() return System.currentTimeMillis() - start } Sandwich Code
  82. public inline fun measureTimeMillis(block: () -> Unit) : Long {

    val start = System.currentTimeMillis() block() return System.currentTimeMillis() - start } Sandwich Code
  83. Delayed Execution

  84. fun printNumbers(oneMillionNumbers: List<Int>) { oneMillionNumbers.forEach { number -> println(number) }

    } Delayed Execution
  85. val oneMillionNumbers = (0..1000000).toList() printNumbers(oneMillionNumbers) Delayed Execution

  86. fun oneMillionNumbers(): () -> List<Int> = { (0..1000000).toList() } printNumbers(oneMillionNumbers())

    Delayed Execution
  87. Kotlin Core Libraries (Because Free is Usually Better)

  88. Collections

  89. (0..1000000) .filter { it % 2 == 0 } .map

    { it.toString() } .map { Pair(it, it.length) } Collections
  90. (0..1000000) .filter { it % 2 == 0 } .map

    { it.toString() } .map { Pair(it, it.length) } // 3 Lists, Expensive! Collections
  91. Sequence

  92. (0..1000000) .asSequence() .filter { it % 2 == 0 }

    .map { it.toString() } .map { Pair(it, it.length) } .toList() Sequence
  93. (0..1000000) .asSequence() .filter { it % 2 == 0 }

    .map { it.toString() } .map { Pair(it, it.length) } .toList() // 1 List, Sorta Cheap ¯\_(ツ)_/¯ Sequence
  94. Kotlin Core Libraries kotlin Core functions and types, available on

    all supported platforms. kotlin.annotation Library support for the Kotlin annotation facility. kotlin.browser - JS Access to top-level properties (document, window etc.) in the browser environment. kotlin.collections Collection types, such as Iterable, Collection, List, Set, Map and related top-level and extension functions. kotlin.comparisons Helper functions for creating Comparator instances. kotlin.concurrent - JVM Utility functions for concurrent programming. kotlin.coroutines.experimental Library support for coroutines, including support for lazy sequences. kotlin.coroutines.experimental.intrinsics Low-level building blocks for libraries that provide coroutine-based APIs. kotlin.dom - JS Utility functions for working with the browser DOM. kotlin.experimental Experimental APIs, subject to change in future versions of Kotlin. kotlin.io IO API for working with files and streams. kotlin.js - JS Functions and other APIs specific to the JavaScript platform. kotlin.jvm - JVM Functions and annotations specific to the Java platform. kotlin.math Mathematical functions and constants. kotlin.properties Standard implementations of delegates for delegated properties and helper functions for implementing custom delegates. kotlin.ranges Ranges, Progressions and related top-level and extension functions. kotlin.reflect Runtime API for Kotlin reflection kotlin.reflect.full - JVM Extensions for Kotlin reflection provided by kotlin-reflect library. kotlin.reflect.jvm - JVM Runtime API for interoperability between Kotlin reflection and Java reflection provided by kotlin-reflect library. kotlin.sequences Sequence type that represents lazily evaluated collections. Top-level functions for instantiating sequences and extension functions for sequences. kotlin.streams - JVM Utility functions for working with Java 8 streams. kotlin.system - JVM System-related utility functions. kotlin.text Functions for working with text and regular expressions. org.khronos.webgl - JS Kotlin JavaScript wrappers for the WebGL API. org.w3c.dom - JS Kotlin JavaScript wrappers for the DOM API. org.w3c.dom.css - JS Kotlin JavaScript wrappers for the DOM CSS API. org.w3c.dom.events - JS Kotlin JavaScript wrappers for the DOM events API. org.w3c.dom.parsing - JS Kotlin JavaScript wrappers for the DOM parsing API. org.w3c.dom.svg - JS Kotlin JavaScript wrappers for the DOM SVG API. org.w3c.dom.url - JS Kotlin JavaScript wrappers for the DOM URL API. org.w3c.fetch - JS Kotlin JavaScript wrappers for the W3C fetch API. org.w3c.files - JS Kotlin JavaScript wrappers for the W3C file API. org.w3c.notifications - JS Kotlin JavaScript wrappers for the Web Notifications API. org.w3c.performance - JS Kotlin JavaScript wrappers for the Navigation Timing API. org.w3c.workers - JS Kotlin JavaScript wrappers for the Web Workers API. org.w3c.xhr - JS Kotlin JavaScript wrappers for the XMLHttpRequest API. https://kotlinlang.org/api/latest/jvm/stdlib/index.html
  95. Why Kotlin?

  96. Less is More The language was designed to be concise.

  97. Kotlin & Java The interoperability is

  98. IDE Support JetBrains provides added functionality for Kotlin in IntelliJ.

  99. Kotlin/Native is Coming Write once, run anywhere.

  100. Kotlin Core Library Expanding The core library will continue to

    add features like Coroutines and Contracts.
  101. Resources • Official Documentation - https://kotlinlang.org/ • Try Online -

    https://try.kotlinlang.org/ • Why JetBrains needs Kotlin - https://blog.jetbrains.com/kotlin/2011/08/ why-jetbrains-needs-kotlin/ • What #android-dev is doing - https://github.com/ActiveCampaign/ android-crm