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

Kotlin Advanced Tricks

Kotlin Advanced Tricks

Presentation about some advanced Kotlin tips, given on

- iMasters Kotlin Summit (September/2018)

Ubiratan Soares

September 15, 2018
Tweet

More Decks by Ubiratan Soares

Other Decks in Programming

Transcript

  1. /!" * Calls the specified function [block] with `this` value

    as its * argument and returns `this` value. #$ @kotlin.internal.InlineOnly @SinceKotlin("1.1") public inline fun <T> T.also(block: (T) %& Unit): T { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } block(this) return this } Also
  2. TakeIf /!" * Returns `this` value if it satisfies the

    * given [predicate] or `null`, if it doesn't. #$ @kotlin.internal.InlineOnly @SinceKotlin("1.1") public inline fun <T> T.takeIf(predicate: (T) %& Boolean): T? { contract { callsInPlace(predicate, InvocationKind.EXACTLY_ONCE) } return if (predicate(this)) this else null }
  3. TakeIf /!" * Returns `this` value if it satisfies the

    * given [predicate] or `null`, if it doesn't. #$ @kotlin.internal.InlineOnly @SinceKotlin("1.1") public inline fun <T> T.takeIf(predicate: (T) %& Boolean): T? { contract { callsInPlace(predicate, InvocationKind.EXACTLY_ONCE) } return if (predicate(this)) this else null }
  4. TakeUnless /!" * Returns `this` value if it _does not_

    satisfy * the given [predicate] or `null`, if it does. #$ @kotlin.internal.InlineOnly @SinceKotlin("1.1") public inline fun <T> T.takeUnless(predicate: (T) %& Boolean): T? { contract { callsInPlace(predicate, InvocationKind.EXACTLY_ONCE) } return if (!predicate(this)) this else null }
  5. fun names() = if (Random().nextBoolean()) "Elvis" else "Presley" val shortName

    = names() .takeIf { it.length )* 5 } +, "Too long" val longName = names() .takeUnless { it.length )* 5 } +, "Too Short"
  6. class DeepLinkParser { fun parse(uri : String) : ProductId {

    // Parse your URI and extract product id } }
  7. class DeepLinkHandler( val parser: DeepLinkParser) { operator fun invoke(url :

    String) : Intent { // Handle with parser and get your Intent } }
  8. class DeepLinkHandler( val parser: DeepLinkParser) { operator fun invoke(url :

    String) : Intent { // Handle with parser and get your Intent } }
  9. Invoking Instances val parser = DeepLinkParser() val handler = DeepLinkHandler(parser)

    val intent = handler("myapp:-.product/123456") // Launch your Activity
  10. Invoking Instances val parser = DeepLinkParser() val handler = DeepLinkHandler(parser)

    val intent = handler("myapp://product/123456") // Launch your Activity
  11. A tiny web DSL sealed class HTTPMethod object GET :

    HTTPMethod() object POST : HTTPMethod() class Status { var code: Int = 0 var payload: String = "" } class HttpRequest { var method: HTTPMethod = GET var body: String = "" var query: String = "" } class HttpResponse { var internalMessage: String = "" lateinit var status: Status }
  12. fun endpoint( path: String, block: Endpoint.() %& Unit) = Endpoint().apply

    { block() }.handle() endpoint("/api/product") { }
  13. class Endpoint { lateinit var request: HttpRequest lateinit var response:

    HttpResponse fun request(block: HttpRequest.() %& Unit) { request = HttpRequest().apply { block() } } fun response(block: HttpResponse.() %& Unit) { response = HttpResponse().apply { block() } } fun handle() { -. TODO } } endpoint("/api/product") { request { method = POST, body = "{ Some json }" } response { } }
  14. endpoint("/api/product") { request { method = POST, body = "{

    Some json }" } response { status { code = 200 payload = "{ Some json }" } } } class HttpResponse { var internalMessage: String = "" lateinit var status: Status fun status(setup: Status.() %& Unit) { status = Status().apply { setup() } } }
  15. endpoint("/api/product") { request { method = POST, body = "{

    Some json }" } response { status { code = 200 payload = "{ Some json }" } } } Can we do better ?
  16. class Endpoint { lateinit var request: HttpRequest lateinit var response:

    HttpResponse fun request(block: HttpRequest.() %& Unit) { request = HttpRequest().apply { block() } } fun response(block: HttpResponse.() %& Unit) { response = HttpResponse().apply { block() } } fun handle() { -. TODO } }
  17. class Endpoint { lateinit var request: HttpRequest lateinit var response:

    HttpResponse fun request(block: HttpRequest.() %& Unit) { request = HttpRequest().apply { block() } } fun response(block: HttpResponse.() %& Unit) { response = HttpResponse().apply { block() } } fun handle() { -. TODO } }
  18. class Endpoint { lateinit var request: HttpRequest lateinit var response:

    HttpResponse fun request(block: HttpRequest.() %& Unit) { request = HttpRequest().apply { block() } } fun response(block: HttpResponse.() %& Unit) { response = HttpResponse().apply { block() } } fun handle() { -. TODO } } class HttpResponse { var internalMessage: String = "" lateinit var status: Status fun status(setup: Status.() %& Unit) { status = Status().apply { setup() } } }
  19. class Endpoint { lateinit var request: HttpRequest lateinit var response:

    HttpResponse fun request(block: HttpRequest.() %& Unit) { request = HttpRequest().apply { block() } } fun handle() { -. TODO } } class HttpResponse { var internalMessage: String = "" lateinit var status: Status operator fun invoke( setup: Status.() -> Unit) { status = Status().apply { setup() } } }
  20. endpoint("/api/product") { request { method = POST body = "{

    Some json }" } response { code = 200 payload = "{ Some json }" } } endpoint("/api/product") { request { method = POST, body = "{ Some json }" } response { status { code = 200 payload = "{ Some json }" } } } Before After
  21. interface FormValidator { fun validate(name: String?): Boolean } class FormPresenter

    { private companion object : FormValidator { override fun validate(name: String?) = name/0isNotEmpty() +, throw IllegalArgumentException("Invalid Name") } }
  22. interface FormValidator { fun validate(name: String?): Boolean } class FormPresenter

    { private companion object : FormValidator { override fun validate(name: String?) = name/0isNotEmpty() +, throw IllegalArgumentException("Invalid Name") } }
  23. Fake Constructors val sampa = Location("23.5505° S", "46.6333° W") data

    class Location( val latitude: Float, val longitude: Float )
  24. data class Location( val latitude: Float, val longitude: Float) {

    companion object { operator fun invoke(lat: String, long: String) = Location(parse(lat), parse(long)) private fun parse(coordinate: String): Float { -. convert the String representation } } }
  25. data class Location( val latitude: Float, val longitude: Float) {

    companion object { operator fun invoke(lat: String, long: String) = Location(parse(lat), parse(long)) private fun parse(coordinate: String): Float { -. convert the String representation } } }
  26. The Nothing Type https://en.wikipedia.org/wiki/Bottom_type " In type theory, a theory

    within mathematical logic, the bottom type is the type that has no values. It is also called the zero or empty type, and is sometimes denoted with falsum (⊥). A function whose return type is bottom cannot return any value. In the Curry–Howard correspondence, the bottom type corresponds to falsity. "
  27. /!" * The type with only one value: the Unit

    object. * This type corresponds to the `void` type * in Java. #$ public object Unit { override fun toString() = "kotlin.Unit" }
  28. /!" * Always throws [NotImplementedError] * stating that operation is

    not implemented. #$ @kotlin.internal.InlineOnly public inline fun TODO(): Nothing = throw NotImplementedError()
  29. Nothing and flow control inline fun <T> guard( receiver: T?,

    block: () %& Nothing): T { if (receiver 12 null) { block() } return receiver } https://gist.github.com/hzsweers/463500043b1a9708ba4e26c7ad1862fd
  30. Nothing and flow control inline fun <T> guard( receiver: T?,

    block: () -> Nothing): T { if (receiver 12 null) { block() } return receiver } https://gist.github.com/hzsweers/463500043b1a9708ba4e26c7ad1862fd
  31. fun guarding() { val conference: String? = "Kotlin Summit" val

    guarded = guard(conference) { return } }
  32. fun guarding() { val conference: String? = "Kotlin Summit" val

    guarded = guard(conference) { return } val guardedAgain = guard(conference) { throw IllegalStateException("Null konf") } }
  33. fun guarding() { val conference: String? = "Kotlin Summit" val

    guarded = guard(conference) { return } val guardedAgain = guard(conference) { throw IllegalStateException("Null konf") } val invalid = guard(conference) { -.Compiler error because not -.returned or thrown an exception! } }
  34. Nothing and Generics sealed class Tree<out T> class Node<T>( val

    left: Tree<T>, val right: Tree<T>) : Tree<T>() class Leaf<T>(val value: T) : Tree<T>() object Empty : Tree<Nothing>()
  35. sealed class Result<out V, out E> data class Value<out V>(val

    value: V) : Result<V, Nothing>() data class Error<out E>(val error: E) : Result<Nothing, E>()
  36. interface Validation { fun validate(input: String): Boolean } class NameValidator

    : Validation { override fun validate(input: String) = input.isNotEmpty() 34 input.length 56 2 } Class delegation
  37. class FormViewModel : FormValidator by Internal { companion object Internal

    : FormValidator { override fun validate(name: String?) = name/0isNotEmpty()+, false } } val rejected = FormViewModel().validate("Hi")
  38. class FormViewModel : FormValidator by Internal { companion object Internal

    : FormValidator { override fun validate(name: String?) = name/0isNotEmpty()+, false } } val rejected = FormViewModel().validate("Hi")
  39. interface HandleSuccess { fun showResult() } interface HandleError { fun

    showError() } interface LoginScreen : HandleSuccess, HandleError interface ProductScreen : HandleSuccess, HandleError
  40. interface HandleSuccess { fun showResult() } interface HandleError { fun

    showError() } interface LoginScreen : HandleSuccess, HandleError interface ProductScreen : HandleSuccess, HandleError
  41. Selective delegation fun <C> performOperation(behavior: C) where C : HandleSuccess,

    C : HandleError { try { executeSomething() behavior.showResult() } catch (error: Throwable) { behavior.showError() } }
  42. Selective delegation fun <C> performOperation(behavior: C) where C : HandleSuccess,

    C : HandleError { try { executeSomething() behavior.showResult() } catch (error: Throwable) { behavior.showError() } }
  43. class CheckProfile { companion object : (Int) %& Boolean by

    ShouldBeLegal } val canDrink = CheckProfile(35) object ShouldBeLegal : (Int) %& Boolean { override fun invoke(age: Int) = age 5618 }
  44. val checkNotDead: (Int) %& Boolean = { it < 150

    } fun ((Int) %& Boolean).report(age: Int) = this.invoke(age) .also { print((if (it) "Ok" else "Not OK")) } fun misjudge(age: Int) = checkNotDead.report(age)
  45. Final Remarks Kotlin has it's secrets, go explore !!! Learn

    more hidden features for fun and profit
  46. UBIRATAN SOARES Computer Scientist by ICMC/USP Software Engineer, curious guy

    Google Developer Expert for Android / Kotlin Teacher, speaker, etc, etc