Share
Embed
Kotlin Advanced Tricks
Presentation about some advanced Kotlin tips, given on
- iMasters Kotlin Summit (September/2018)
Ubiratan Soares PRO
September 15, 2018
Transcript
67 slides
-
/!" * 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 -
fun validate(name: String) = name.length in 2'(20 fun saveUser(name: String)
= validate(name) .also { saveWith(name) } -
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 } -
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 } -
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 } -
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" -
class DeepLinkParser { fun parse(uri : String) : ProductId {
// Parse your URI and extract product id } } -
class DeepLinkHandler( val parser: DeepLinkParser) { operator fun invoke(url :
String) : Intent { // Handle with parser and get your Intent } } -
class DeepLinkHandler( val parser: DeepLinkParser) { operator fun invoke(url :
String) : Intent { // Handle with parser and get your Intent } } -
Invoking Instances val parser = DeepLinkParser() val handler = DeepLinkHandler(parser)
val intent = handler("myapp:-.product/123456") // Launch your Activity -
Invoking Instances val parser = DeepLinkParser() val handler = DeepLinkHandler(parser)
val intent = handler("myapp://product/123456") // Launch your Activity -
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 } -
class Endpoint { lateinit var request: HttpRequest lateinit var response:
HttpResponse fun handle() { -. TODO } } -
fun endpoint( path: String, block: Endpoint.() %& Unit) = Endpoint().apply
{ block() }.handle() endpoint("/api/product") { } -
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 { } } -
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() } } } -
endpoint("/api/product") { request { method = POST, body = "{
Some json }" } response { status { code = 200 payload = "{ Some json }" } } } Can we do better ? -
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 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 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() } } } -
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() } } } -
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 -
interface FormValidator { fun validate(name: String?): Boolean } class FormPresenter
{ private companion object : FormValidator { override fun validate(name: String?) = name/0isNotEmpty() +, throw IllegalArgumentException("Invalid Name") } } -
interface FormValidator { fun validate(name: String?): Boolean } class FormPresenter
{ private companion object : FormValidator { override fun validate(name: String?) = name/0isNotEmpty() +, throw IllegalArgumentException("Invalid Name") } } -
Fake Constructors val sampa = Location("23.5505° S", "46.6333° W") data
class Location( val latitude: Float, val longitude: Float ) -
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 } } } -
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 } } } -
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. " -
/!" * 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" } -
/!" * Always throws [NotImplementedError] * stating that operation is
not implemented. #$ @kotlin.internal.InlineOnly public inline fun TODO(): Nothing = throw NotImplementedError() -
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 -
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 -
fun guarding() { val conference: String? = "Kotlin Summit" val
guarded = guard(conference) { return } } -
fun guarding() { val conference: String? = "Kotlin Summit" val
guarded = guard(conference) { return } val guardedAgain = guard(conference) { throw IllegalStateException("Null konf") } } -
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! } } -
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>() -
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>() -
interface Validation { fun validate(input: String): Boolean } class NameValidator
: Validation { override fun validate(input: String) = input.isNotEmpty() 34 input.length 56 2 } Class delegation -
class FormViewModel : FormValidator by Internal { companion object Internal
: FormValidator { override fun validate(name: String?) = name/0isNotEmpty()+, false } } val rejected = FormViewModel().validate("Hi") -
class FormViewModel : FormValidator by Internal { companion object Internal
: FormValidator { override fun validate(name: String?) = name/0isNotEmpty()+, false } } val rejected = FormViewModel().validate("Hi") -
interface HandleSuccess { fun showResult() } interface HandleError { fun
showError() } interface LoginScreen : HandleSuccess, HandleError interface ProductScreen : HandleSuccess, HandleError -
interface HandleSuccess { fun showResult() } interface HandleError { fun
showError() } interface LoginScreen : HandleSuccess, HandleError interface ProductScreen : HandleSuccess, HandleError -
Selective delegation fun <C> performOperation(behavior: C) where C : HandleSuccess,
C : HandleError { try { executeSomething() behavior.showResult() } catch (error: Throwable) { behavior.showError() } } -
Selective delegation fun <C> performOperation(behavior: C) where C : HandleSuccess,
C : HandleError { try { executeSomething() behavior.showResult() } catch (error: Throwable) { behavior.showError() } } -
class CheckProfile { companion object : (Int) %& Boolean by
ShouldBeLegal } val canDrink = CheckProfile(35) object ShouldBeLegal : (Int) %& Boolean { override fun invoke(age: Int) = age 5618 } -
What if I told you that extensions are not only
for objects ??? -
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) -
Final Remarks Kotlin has it's secrets, go explore !!! Learn
more hidden features for fun and profit -
UBIRATAN SOARES Computer Scientist by ICMC/USP Software Engineer, curious guy
Google Developer Expert for Android / Kotlin Teacher, speaker, etc, etc