Reduce this to a simple lambda - kotlin

I would like to simplify this code by reducing it to just a lambda. The interface has only one function. I'm not sure how to replace the override part of the code with just a lambda expression:
interface ITextWatcher {
fun onTextChanged(text: String) {
}
}
val textChangeHandler = object: ITextWatcher {
override fun onTextChanged(text: String)
var t = text
}
}
I'm looking for something like this:
val textChangeHandler = object: ITextWatcher {text ->
}
But that won't compile.

The syntax is val textChangeHandler = ITextWatcher {text -> ... }, but it doesn't work for interfaces declared in Kotlin, only for Java ones (at least for now).
Use (String) -> Unit directly instead. Or declare a function to convert one to another:
inline fun ITextWatcher(crossinline f: (String) -> Unit) = object : ITextWatcher {
override fun onTextChanged(text: String) {
f(text)
}
}
val textChangeHandler = ITextWatcher {text -> ... }
if you want.

Related

How to use Either monad and avoid nested flatMap

I'm in a situation where I'm trying to setup some data and then call a service. Each step can fail, so I'm trying to use Arrow's Either to manage this.
But I'm ending up with a lot of nested flatMaps.
The following code snippet illustrates what I'm trying to do:
import arrow.core.Either
import arrow.core.flatMap
typealias ErrorResponse = String
typealias SuccessResponse = String
data class Foo(val userId: Int, val orderId: Int, val otherField: String)
data class User(val userId: Int, val username: String)
data class Order(val orderId: Int, val otherField: String)
interface MyService {
fun doSomething(foo: Foo, user: User, order: Order): Either<ErrorResponse, SuccessResponse> {
return Either.Right("ok")
}
}
fun parseJson(raw: String): Either<ErrorResponse, Foo> = TODO()
fun lookupUser(userId: Int): Either<ErrorResponse, User> = TODO()
fun lookupOrder(orderId: Int): Either<ErrorResponse, Order> = TODO()
fun start(rawData: String, myService: MyService): Either<ErrorResponse, SuccessResponse> {
val foo = parseJson(rawData)
val user = foo.flatMap {
lookupUser(it.userId)
}
//I want to lookupOrder only when foo and lookupUser are successful
val order = user.flatMap {
foo.flatMap { lookupOrder(it.orderId) }
}
//Only when all 3 are successful, call the service
return foo.flatMap { f ->
user.flatMap { u ->
order.flatMap { o ->
myService.doSomething(f, u, o)
}
}
}
}
I'm sure there is a better way to do this. Can someone help me with an idiomatic approach?
You can use the either { } DSL, this is available in a suspend manner or in a non-suspend manner through the either.eager { } builder.
That way you can use suspend fun <E, A> Either<E, A>.bind(): A.
Rewriting your code example:
fun start(rawData: String, myService: MyService): Either<ErrorResponse, SuccessResponse> =
either.eager {
val foo = parseJson(rawData).bind()
val user = lookupUser(foo.userId).bind()
val order = lookupOrder(foo.orderId).bind()
myService.doSomething(foo, user, order).bind()
}
If you run into an Either.Left, then bind() will short-circuit the either.eager block and return with the encountered Either.Left value.

What the differents variables will be destructured when I use rememberSaveable?

The Code A is from offical sample code here.
The code val (currentSection, updateSection) = rememberSaveable { mutableStateOf(tabContent.first().section) } will create two variables, one is currentSection, another is updateSection.
According to the Hint of Android Studio, I find the following definition
val currentSection: Sections
val updateSection: (Sections) → Unit
I read the source code of both tabContent and rememberSaveable, but I can't understand why the rememberSaveable can destructure it to two different variables (Sections And (Sections) → Unit). Why can't the rememberSaveable destructure it to three different variables with other types?
Code A
#Composable
fun InterestsRoute(
interestsViewModel: InterestsViewModel,
isExpandedScreen: Boolean,
openDrawer: () -> Unit,
scaffoldState: ScaffoldState = rememberScaffoldState()
) {
val tabContent = rememberTabContent(interestsViewModel)
val (currentSection, updateSection) = rememberSaveable {
mutableStateOf(tabContent.first().section)
}
InterestsScreen(
tabContent = tabContent,
currentSection = currentSection,
isExpandedScreen = isExpandedScreen,
onTabChange = updateSection,
openDrawer = openDrawer,
scaffoldState = scaffoldState
)
}
#Composable
fun rememberTabContent(interestsViewModel: InterestsViewModel): List<TabContent> {
...
return listOf(topicsSection, peopleSection, publicationSection)
}
class TabContent(val section: Sections, val content: #Composable () -> Unit)
The destructing that you are referring to has actually nothing to do with rememberSaveable.
The rememberSaveable { mutableStateOf(...) } function returns a MutableState and this is what can be destructured.
interface MutableState<T> : State<T> {
override var value: T
operator fun component1(): T
operator fun component2(): (T) -> Unit
}
Here you can see the two components that you are referring to ( T and (T) -> Unit)

Add a side-effect to a function in a generic way

How can I write a Kotlin generic function that takes a function as an argument and adds a side-effect to it? For instance,
fun something(one: Int, two: String): String { return "${one}, ${two}" }
fun somethingElse(arg: Array<String>): String { return "${arg}" }
val w1 = wrapped(::something)
w1(42, "hello")
val w2 = wrapped(::somethingElse)
w2(arrayOf("ichi", "ni"))
The following works for functions that take only a single parameter:
fun <A, R> wrapped(theFun: (a: A) -> R): (a: A) -> R {
return { a: A ->
theFun(a).also { println("wrapped: result is $it") }
}
}
To make this work with an arbitrary number of arguments, I'd need some construct that gives me the type of the argument list. Unfortunately, the Function generic can't be used since it takes only one parameter. The following does not compile:
fun <A, R> wrapped(theFun: Function<A, R>): Function<A, R> {
return { args: A ->
theFun(*args).also { println("wrapped: result is ${it}") }
}
}
Or maybe I could use varargs? Does not seem to work with lambdas. Or Kotlin reflection?
Solution using reflection:
class KFunctionWithSideEffect<R>(private val f: KFunction<R>, private val sideEffect: (R) -> Unit) : KFunction<R> by f {
override fun call(vararg args: Any?) = f.call(*args).also { sideEffect(it) }
override fun callBy(args: Map<KParameter, Any?>) = f.callBy(args).also { sideEffect(it) }
}
fun <R> wrapped(theFun: KFunction<R>, sideEffect: (R) -> Unit = { str -> println("wrapped: result is $str") }) =
KFunctionWithSideEffect(theFun, sideEffect)
Usage:
val w1 = wrapped(::something)
w1.call(42, "hello")
val w2 = wrapped(::somethingElse)
w2.call(arrayOf("ichi", "ni"))

How to pass is operator parameter through function in Kotlin

val k = " asdfasdf "
fun test() {
if(k is String) {
// Do something
}
}
So, how do I pass that String through the function calls
eg:
fun test(xxxx) {
if(k is xxxx) {
// do something
}
}
Like this:
inline fun <reified T> testType(k: Any) {
if(k is T) {
println("is a ${T::class.simpleName}")
} else {
println("is not a ${T::class.simpleName}")
}
}
Call it like this:
test<String>("Hello") // is a String
test<String>(1) // is no String
Here some further reading.
There are two possibilities, depending on your needs.
1. Use inline and a reified type parameter
You can use the reified keyword on the type parameter in combination with an inline function:
inline fun <reified T> test(k: Any) {
if (k is T) {
println("k is a T!")
}
}
See the documentation on reified.
2. Use KClass<T>
If you do not want to or cannot make your function inline you can use a KClass parameter:
fun <T : Any> test(k: Any, type: KClass<T>) {
if (type.isInstance(k)) {
println("k is a T!")
}
}
You can either use a predicate, e.g.:
fun testIt(predicate: (Any?) -> Boolean) {
if (predicate(k)) {
println("matches!")
} else println("nope")
}
and call it as follows:
testIt { it is String }
testIt { it is Int }
Or you can use a reified type:
inline fun <reified T> testIt() {
when (k) {
is T -> println("matches!")
else -> println("nope")
}
}
and call it like:
testIt<String>()
testIt<Int>()
For simplicity I kept your current variable inside the testIt-method... you may want to redesign that ;-)
I basically assumed a member variable as follows: var k : Any? = null
inline fun <reified T> isType(obj: Any): Boolean {
return obj is T
}
fun main(args: Array<String>) {
val test = "This is a String"
if (isType<String>(test)) {
println("Success")
} else {
println("Failure")
}
}

Add new key-value represented by a `Pair` to a `MutableMap`

I currently have this class with dsl like building ability
class GRLMessage {
var headerMap : MutableMap<String, String> = mutableMapOf()
lateinit var methodType : GRLMethod
lateinit var multipartObject : IGRLMultipart
fun message(closure: GRLMessage.() -> Unit) : GRLMessage {
closure()
return this
}
fun method(closure: GRLMessage.() -> GRLMethod) : GRLMessage {
methodType = closure()
return this
}
fun headers(closure: GRLMessage.() -> Unit) : GRLMessage {
closure()
return this
}
fun header(closure: GRLMessage.() -> Pair<String, String>) : GRLMessage {
var pair = closure()
headerMap.put(pair.first, pair.second)
return this
}
fun multipart(closure: GRLMessage.() -> IGRLMultipart) : GRLMessage {
multipartObject = closure()
return this
}
}
And I test it like this
class GRLMessageTest {
data class DummyMultipart(val field: String) : IGRLMultipart {
override fun getContent() {
this
}
}
#Test fun grlMessageBuilderTest() {
val grlMessage = GRLMessage().message {
method { GRLMethod.POST }
headers {
header { Pair("contentType", "object") }
header { Pair("objectType", "DummyMultipart") }
}
multipart { DummyMultipart("dummy") }
}
val multipart = DummyMultipart("dummy")
val headers = mapOf(
Pair("contentType", "object"),
Pair("objectType", "DummyMultipart")
)
val method = GRLMethod.POST
assertEquals(multipart, grlMessage.multipartObject)
assertEquals(method, grlMessage.methodType)
assertEquals(headers, grlMessage.headerMap)
}
}
But despite providing
header { Pair("contentType", "object") }
I still have to evaluate closure inside header method and directly put key and value into my MutableMap
fun header(closure: GRLMessage.() -> Pair<String, String>) : GRLMessage {
var pair = closure()
headerMap.put(pair.first, pair.second)
return this
}
Is there a better way adding entries to Map?
Does your headerMap need to be a var? If not, you can change it to a val and use headerMap += closure().
Adding an extension function makes your fluent methods more obviously fluent:
fun <T: Any> T.fluently(func: ()->Unit): T {
return this.apply { func() }
}
With that your fluent function is always clear about its return:
fun header(closure: GRLMessage.() -> Pair<String, String>) : GRLMessage {
return fluently { headerMap += closure() }
}
Which is really the same as:
fun header(closure: GRLMessage.() -> Pair<String, String>) : GRLMessage {
return this.apply { headerMap += closure() }
}
But the extension function adds a touch of readability.
Above I use the answer given in by #Ruckus for solving your specific question of adding a Pair to the headerMap. But you have other options that you might want to know about for other use cases of your DSL...
You can use let, apply or with which would allow any type of decomposition of the results of closure() call (maybe it is more complicated than Pair in the future). All of these are basically the same, minus their resulting value:
with(closure()) { headerMap.put(this.first, this.second) }
closure().apply { headerMap.put(this.first, this.second) }
closure().let { headerMap.put(it.first, it.second) }
Using let or apply is nice if you want to handle a case where closure() allows nullable return, in which case you might want to take action only if not null:
closure()?.apply { headerMap.put(this.first, this.second) }
closure()?.let { headerMap.put(it.first, it.second) }
Other notes about your code:
use val instead of var unless you have no other choice
lateinit (or the similar Delegates.notNull()) seem dangerous to use in an uncontrolled lifecycle where there is no guarantee it will be completed, because the error message will be confusing and happen at some unexpected time in the future. There are likely other ways to solve this with a DSL that chains calls to create more of a multi-step grammar
You can shorten code by only having types on one side of the assignment, for example:
val myMap = mutableMapOf<String, String>()
instead of
var myMap : MutableMap<String, String> = mutableMapOf()
Well for now as a solution I created extension for MutableMap
fun MutableMap<String, String>.put(pair : Pair<String, String>) {
this.put(pair.first, pair.second)
}
Which allowed me to write like this
fun header(closure: GRLMessage.() -> Pair<String, String>) : GRLMessage {
headerMap.put(closure())
return this
}