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

Kotlin Lunch and Learn

Cody Engel
September 21, 2018

Kotlin Lunch and Learn

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

Cody Engel

September 21, 2018
Tweet

More Decks by Cody Engel

Other Decks in Technology

Transcript

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

    more productive by switching to a more expressive language.”
  2. var a = 1 val s1 = "a is $a"

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

    is $a” // a was 1 but now is 2 String Templates
  4. fun maxOf(a: Int, b: Int): Int { if (a >

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

    a else b Conditional Expressions
  6. val maybeNull: String? = null val notNull: String = if

    (maybeNull != null) maybeNull else "" Handling Null
  7. val listWithNulls: List<String?> = listOf("Kotlin", null) for (item in listWithNulls)

    { item?.let { println(it) } //prints Kotlin and ignores null } Handling Null
  8. 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
  9. 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
  10. when (x) { is Int -> print(x + 1) is

    String -> print(x.length + 1) is IntArray -> print(x.sum()) } Type Casting
  11. –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.”
  12. 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
  13. 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
  14. –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.”
  15. –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.”
  16. 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
  17. 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
  18. 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
  19. 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" }
  20. val String.asBoolean: Boolean get() = this != “0" //… val

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

    != "0" //… val pAdmin: String? = null pAdmin.asBoolean Extension Property
  22. 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
  23. private ExpensiveObjectToCreate _expensiveObject = null; ExpensiveObjectToCreate getExpensiveObject() { if (_expensiveObject

    == null) { _expensiveObject = new ExpensiveObjectToCreate(); } return _expensiveObject; } Property Delegation
  24. 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
  25. 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
  26. 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
  27. 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
  28. 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
  29. 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
  30. 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
  31. –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.”
  32. public fun measureTimeMillis(block: () -> Unit) : Long { val

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

    val start = System.currentTimeMillis() block() return System.currentTimeMillis() - start } Sandwich Code
  34. (0..1000000) .filter { it % 2 == 0 } .map

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

    { it.toString() } .map { Pair(it, it.length) } // 3 Lists, Expensive! Collections
  36. (0..1000000) .asSequence() .filter { it % 2 == 0 }

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

    .map { it.toString() } .map { Pair(it, it.length) } .toList() // 1 List, Sorta Cheap ¯\_(ツ)_/¯ Sequence
  38. 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
  39. Kotlin Core Library Expanding The core library will continue to

    add features like Coroutines and Contracts.
  40. 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