Can we pass two higher order functions or more than one, in function's parameter?
If so, then how we going to call that function which contain those two or more than one higher order functions as a parameter...
Of couse you can. You can have any number of lambda parameters just like for parameters of any other type.
Even Kotlins standard library makes use of that. For example the generateSequence function.
generateSequence(seedFunction = { 1 }, nextFunction = { it + 1 })
The only difference to a non-lambda parameter is that you can omit the parentheses if the last parameter of your function is a lambda. So you could call generateSequence like this too:
generateSequence(seedFunction = { 1 }) { it + 1 }
Wording
There might be a misunderstanding of what a Higher-Order function is:
GeeksForGeeks:
In Kotlin, a function which can accepts a function as parameter or can
returns a function is called Higher-Order function.
And now the definition for functions:
Kotlinlang:
Kotlin functions are first-class, which means that they can be stored
in variables and data structures, passed as arguments to and returned
from other higher-order functions. You can operate with functions in
any way that is possible for other non-function values.
Conclusion
Functions can be passed as parameters into methods - just as many as you like. High-order is just a (descriptive) type, which means that your method either takes functions as parameters, or returns a function.
Example:
fun <T> takeFiveFunctions(
block1 : () -> Unit,
block2 : (T) -> Unit,
block3 : () -> T,
block4 : (T) -> T,
block5 : (List<T>) -> T
) : Boolean = true
fun main() {
takeFiveFunctions<Int>(
block1 = { /*do something 1*/ },
block2 = { print(it) },
block3 = { 2 },
block4 = { it * 3 },
block5 = { it.first() }
)
}
EDIT
but some other syntax says we can take out lambda from parentheses
Kotlinlang says:
In Kotlin, there is a convention: if the last parameter of a function
is a function, then a lambda expression passed as the corresponding
argument can be placed outside the parentheses:
Using my previous example, it would look like this:
fun main() {
takeFiveFunctions<Int>(
block1 = { /*do something 1*/ },
block2 = { print(it) },
block3 = { 2 },
block4 = { it * 3 }
) { it.first()}
}
Yes, why not. You can just do that:
fun <T1, T2, T3> Collection<T1>.higherOrder(
firstFun: (T1)->T2,
secondFun: (T2)->T3)
: List<T3> {
return this.map(firstFun).map(secondFun)
}
Invocation:
val result = listOf(3.14, 6.9, 42.0).higherOrder({ it.toInt() }, { it.toString() })
// ["3", "6", "42"]
Kotlin allows to move last lambda parameter outside parameter list, so you can also write:
val result = listOf(3.14, 6.9, 42.0).higherOrder({ it.toInt() }) { it.toString() }
But in case of multiple functional parameters, that's bad practice. The best you can do is to specify parameter names explicitly:
val result = listOf(3.14, 6.9, 42.0).higherOrder(
firstFun = { it.toInt() },
secondFun = { it.toString() }
)
Which is much more readable.
Related
I'm trying to read a list of objects from the database and mapping it to another type of list.
// Returns either a Failure or the expected result
suspend fun getCountries(): Either<Failure, List<CountryItem>> {
// Get the result from the database
val result = countryLocalDataSource.getCountries()
// Left means Failure
if (result.isLeft) {
// Retrieve the error from the database
lateinit var error: Failure
result.either({
error = it
}, {})
// Return the result
return Either.Left(error)
}
// The database returns a List of Country objects, we need to map it to another object (CountryItem)
val countryItems: MutableList<CountryItem> = mutableListOf()
// Iterate the Country List and construct a new List of CountryItems
result.map { countries -> {
countries.forEach {
// Assign some values from an Enum (localized string resources)
val countryEnumValue = Countries.fromId(it.id)
countryEnumValue?.let { countryIt ->
val countryStringNameRes = countryIt.nameStringRes;
// Create the new CountryItem object (#StringRes value: Int, isSelected: Bool)
countryItems.add(CountryItem(countryStringNameRes, false))
}
}
} }
// Because this is a success, return as Right with the newly created List of CountryItems
return Either.Right(countryItems)
}
For the sake of readability I didn't included the whole Repository or the DAO classes and I have left comments in the code snippet above.
In a nutshell: I'm using Kotlin's Coroutines for accessing the database in a separated thread and I'm handling the response on the UI Thread. Using the Either class in order to return two different results (failure or success).
The above code works, however It's too ugly. Is this the right approach to deliver the result?
What I'm trying to do is to refactor the code above.
The whole problem is caused by the two different object types. The Database Data Source API is returning an Either<Failure, List<Country>>, meanwhile the function is expected to return an Either<Failure, List<CountryItem>>.
I can't deliver a List<CountryItem> directly from the Database Data Source API, because Android Studio doesn't let me compile the project (entities implementing interfaces, compile error, etc.). What I'm trying to achieve is to map the Either result in a nicer way.
Try using Kotlin's Result
So in your case you can write something like:
return result.mapCatching { list: List<Country> -> /*return here List<CountryItem>>*/ }
And for checking result call:
result.fold(
onSuccess = {...},
onFailure = {...}
)
In order to invoke a constructor you should call Result.success(T) or Result.failure(Throwable)
Unfortunately, you'll also need to suppress use-as-return-type warnings How to
You can simplify by checking the type of Either and accessing the value directly. In your case:
access Left via result.a -> Failure
access Right via result.b -> List<Country>
ex:
when (result) {
is Either.Left -> {
val failure: Failure = result.b
...
}
is Either.Right -> {
val countries: List<Country> = result.b
...
}
}
An alternative is to use the either() function (normally this is called fold()):
result.either(
{ /** called when Left; it == Failure */ },
{ /** called when Right; it == List<Country> */ }
)
Assume your Country class is defined as follow:
data class Country(val name: String) {}
and your CountryItem class is defined as follow:
data class CountryItem(private val name: String, private val population: Int) {}
and your CountryLocalDataSource class with a method getCountries() like this:
class DataSource {
suspend fun getCountries(): Either<Exception, List<Country>> {
return Either.Right(listOf(Country("USA"), Country("France")))
//return Either.Left(Exception("Error!!!"))
}
}
then the answer to your question would be:
suspend fun getCountryItems(): Either<Exception, List<CountryItem>> {
when (val countriesOrFail = DataSource().getCountries()) {
is Either.Left -> {
return Either.Left(countriesOrFail.a)
}
is Either.Right -> {
val countryItems = countriesOrFail.b.map {
CountryItem(it.name, 1000)
}
return Either.Right(countryItems)
}
}
}
To call your getCountryItems(), here is an example:
suspend fun main() {
when (val countriesOrFail = getCountryItems()) {
is Either.Left -> {
println(countriesOrFail.a.message)
}
is Either.Right -> {
println(countriesOrFail.b)
}
}
}
Here's the sample code in the playground: https://pl.kotl.in/iiSrkv3QJ
A note about your map function:
I'm guessing you don't actually need the result to be a MutableList<CountryItem> but you had to define so because you want to add an element as you iterate through the input list List<Country>.
Perhaps the following is the case: If you have a List<Country> with 2 elements like in the example, and you want to map so that the result becomes a List<CountryItem> with also 2 corresponding elements, then you don't need to call forEach inside a fun that gets passed to the higher-order function map. But this may be an entirely new question.
In my app I have two services and both of them have a method that makes a requests and then returns an Observable of different type.
I want to display in a RecyclerView a list composed of the result of combining these two Observables. I googled about this and found the zip() method that seems to do exactly what I want. I'm trying to implement it but I don't know how to do it correctly.
While I was googling, I came up with this this article which seems to explain it clearly. Even though the author is using Singles while I am using Observables.
As far as I understand how zip() works, I know I have to pass every Observable I want to "zip" and then I must specify a function that will compose my final Observable, right?
This is my code so far:
interface InvitationService {
#GET("foo/{userId}")
fun getFooByUser(#Path("userId") userId: String): Observable<Response<ArrayList<Foo>>>
}
interface InvitationService {
#GET("bar/{userId}")
fun getBarByUser(#Path("userId") userId: String): Observable<Response<ArrayList<Bar>>>
}
class FooRemoteDataSource : FooDataSource {
private var apiService: FooService
fun getFooByUser(userId:String) {
return apiService.getFooByUser(userId)
}
}
class BarRemoteDataSource : BarDataSource {
private var apiService: BarService
fun getBarByUser(userId:String) {
return apiService.getBarByUser(userId)
}
}
class FooRepository(private val remoteDataSource: InvitationRemoteDataSource) : FooDataSource {
override fun getFooByUser(userId: String): Observable<Response<ArrayList<Foo>>> {
return remoteDataSource.getFooByUser(userId)
}
}
class BarRepository(private val remoteDataSource: BarRemoteDataSource) : BarDataSource {
override fun getBarByUser(userId: String): Observable<Response<ArrayList<Bar>>> {
return remoteDataSource.getBarByUser(userId)
}
}
And here is where I'm actually stuck:
class ListPresenter(var listFragment: ListContract.View?,
val fooRepository: FooRepository,
val barRepository: BarRepository) : ListContract.Presenter {
fun start() {
loadList()
}
private fun loadLists() {
//HERE IS WHERE IM STUCK
Observable.zip(fooRepository.getFooByUser(userId).subscribeOn(Schedulers.io()),
barRepository.getBarByUser(userId).subscribeOn(Schedulers.io()),
)
// AFTER 'ZIPPING' THE OBSERVABLES
// I NEED TO UPDATE THE VIEW ACCORDINGLY
}
}
I don't know how to call zip() properly, I know that I must pass a function but I don't get it because in the article linked above the author is using a Function3 because he has 3 Observables.
As I only have 2, I don't know how to do it. If open curly braces after a comma inside the method args, it requires me to return a BiFunction<ArrayList<Foo>, ArrayList<Bar>> which is what I don't know how to specify.
Would someone explain it to me?
For Kotlin you should use RxKotlin rather than RxJava. BiFunction, Function3 come from RxJava. With RxKotlin you can use lambdas instead.
As far as I understand how zip() works, I know I have to pass every Observable I want to "zip" and then I must specify a function that will compose my final Observable, right?
Correct, and here is a minimal example, which demonstrates how to do it.
Example 1
val observable1 = listOf(1, 2, 3).toObservable()
val observable2 = listOf(4, 5, 6).toObservable()
val zipped = Observables.zip(observable1, observable2) { o1, o2 -> o1 * o2}
In this example you have two observables, each emitting integers. You pass them to zip and as third argument a lambda which defines a way to "cobmine them". In this case it multiplies them.
The resulting observable zipped will emit: 4, 10 and 18.
Example 2
Here another example zipping three observables which are not all of the same type:
val obs1 = listOf("on", "tw", "thre").toObservable()
val obs2 = listOf("n", "o", "e").toObservable()
val obs3 = listOf(1, 2, 3).toObservable()
val zipped = Observables.zip(obs1, obs2, obs3) { o1, o2, o3 ->
"$o1$o2 = $o3"
}
Here, each element of the resulting observable will be a string: "one = 1", "two = 2", "three = 3"
Zipping two Observables of different types using BiFunction
override fun getCommoditiesAndAddresses() {
view.showProgress()
view.hideViews()
Observable.zip(Commo24Retrofit.createAuthService(RateAPIService::class.java)
.getCommodities(),
Commo24Retrofit.createAuthService(RateAPIService::class.java)
.getLocations(GetLocationsRequest(getOrgId())),
BiFunction { commodityResponse: GetCommoditiesResponse, locationsResponse: GetLocationsResponse ->
handleCommoditiesAndAddresses(commodityResponse, locationsResponse)
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
view.hideProgress()
view.showViews()
view.handleCommodities(it?.commodities)
view.handleLocations(it?.locations)
}, { throwable ->
view.hideProgress()
view.handleFailure(throwable.getErrorMessage(context))
})
}
Look, how I'm handling the response:
private fun handleCommoditiesAndAddresses(commodityResponse: GetCommoditiesResponse, locationsResponse: GetLocationsResponse): CommoditiesAddresses {
return CommoditiesAddresses(commodityResponse.commodityList, locationsResponse.addressList)
}
Here, check the API Service:
interface RateAPIService {
#POST("get-org-address")
fun getLocations(#Body getLocationsRequest: GetLocationsRequest): Observable<GetLocationsResponse>
#POST("get-commodity-list")
fun getCommodities(): Observable<GetCommoditiesResponse>
}
If you have any doubt you can comment it out.
New at Kotlin here and trying to learn the best way to use the higher order functions and passing lambdas. I've created this method to call an API and return an object created from a string OR return a failure if something went wrong.
fun getDeviceStatus(onSuccess: (Device) -> Unit, onFailure: ((String) -> Unit)? = null) {
FuelClient.get(DEVICE_URL,
success = { responseString ->
val adapter = MoshiUtil.moshi.adapter(Device::class.java)
val deivce= adapter.fromJson(responseString)!!
onSuccess(device)
},
failure = { onFailure?.invoke(it.message!!)})
}
I can use this function fine like so:
DeviceService.getDeviceStatus(
{ w ->
print("device")
},
{ e -> print(e) })
But it bothers me a bit that I can't see the name of the functions to see what each function does. I"m wondering if there is a cleaner/better way to do this, like
DeviceService.getDeviceStatus(){
onSuccess{print("device")}
onFailure{print("error")}
}
or maybe
DeviceService.getDeviceStatus()
.onSuccess{print("device")}
.onFailure{print("error")}
But those gives errors. Any thoughts on how to best handle the onSuccess/onFailure use case that is very common? Thx
You can attach a name to each variable in kotlin. Change your code like this
DeviceService.getDeviceStatus(
onSuccess = { w ->
print("device")
},
onFailure = { e -> print(e) })
For this specific case, when the second lambda is optional, infix functions work very well:
sealed class DeviceStatusResult {
abstract infix fun onFailure(handler: (String) -> Unit)
}
class DeviceStatusSuccess(val device: Device) : DeviceStatusResult() {
override fun onFailure(handler: (String) -> Unit) = Unit
}
class DeviceStatusFailure(val errorMessage: String) : DeviceStatusResult() {
override fun onFailure(handler: (String) -> Unit) = handler(errorMessage)
}
fun getDeviceStatus(onSuccess: (Device) -> Unit): DeviceStatusResult {
// get device status
// if (success)
val device = Device()
onSuccess(device)
return DeviceStatusSuccess(device)
// else
// return DeviceStatusFailure(message)
}
Then it can used like
getDeviceStatus { device ->
println(device)
} onFailure { errorMessage ->
System.err.println(errorMessage)
}
Maybe onFailure should be called orFail or something like that.
It is good when the second argument is optional, but not so much otherwise because it doesn't force the user to actually supply a failure handler. And I don't think it's a good idea because it will be too easy to accidentally omit a failure handler. It's much better to force the user to provide one, even if it happens to be an empty one. Therefore, it is better to use named arguments for this case, even though nothing forces to actually name them.
For example we have a class which needs to have more than one function such as two functions as parameter:
class TestClass internal constructor(
private val onClickShowName: (String) -> Unit,
private val onClickShowSurname: (String) -> Unit
) { //Your work. }
Then you need to create val as TestClass:
class MainActivity {
val mTestClass = TestClass(
onClickShowName = {dataText: String -> Log.i("TEST", dataText)},
onClickShowSurname = {dataText: String -> Log.i("TEST", dataText)}
)
}
Is it possible to call a function with multiple lambda functions?
If so, how can I invoke the following function?
fun post(path: String,
params: JSONObject,
completionHandler: (response: JSONObject?) -> Unit,
errorCompletionHandler: (error: VolleyError?) -> Unit
)
Yes, you can have as many lambdas as you like. The shown post can be invoked as follows:
post("/a", "json", {response-> println(response) }, { error-> println(error)})
It's also possible to lift the last lambda out of the parentheses as described in the documentation:
In Kotlin, there is a convention that if the last parameter to a function is a function, and you're passing a lambda expression as the corresponding argument, you can specify it outside of parentheses.
Applied to your code, this means:
post("/a", "json", { response -> println(response) }) { error ->
println(error)
}
You would define the lambdas as shown below. You can assign them to variables to make the code more readable. This becomes especially handy if you lambda become bigger.
val completionHandler: (JSONObject?) -> Unit = { response ->
// ...
}
val errorCompletionHandler: (VolleyError?) -> Unit = { error ->
// ...
}
post("/path", jsonObject, completionHandler, errorCompletionHandler)
Or you can define functions which you pass using a reference:
fun errorCompletionHandler(error: VolleyError?) {}
fun completionHandler(response: JSONObject?) {}
post("/path", jsonObject, ::completionHandler, ::errorCompletionHandler)
Notice that Unit can be ommitted here because it is the implicit return type if nothing else was specified.
I'm converting my function having lambda as parameter into inline function for performance improvement.
I have list of lambda of type MutableList<(Authenticate) -> Unit> variable as data member in class. When I try to adding lambda parameter into the list.
Kotlin compiler says:
Illegal usage of inline parameter callback
Here is the code
// Some code skipped
object Odoo {
val pendingAuthenticateCallbacks = mutableListOf<(Authenticate) -> Unit>()
inline fun authenticate(
login: String, password: String, database: String,
quick: Boolean = false, crossinline callback: Authenticate.() -> Unit
) {
// Following statement has error saying
// Illegal usage of inline parameter callback. add 'noinline' modifier to parameter declaration.
pendingAuthenticateCallbacks += callback
// Error in above statement
if (pendingAuthenticateCallbacks.size == 1) {
// Retrofit2 Object boxing code skipped
val call = request.authenticate(requestBody)
call.enqueue(object : Callback<Authenticate> {
override fun onFailure(call: Call<Authenticate>, t: Throwable) {
(pendingAuthenticateCallbacks.size - 1 downTo 0)
.map { pendingAuthenticateCallbacks.removeAt(it) }
.forEach {
it(Authenticate(httpError = HttpError(
Int.MAX_VALUE,
t.message!!
)))
}
}
override fun onResponse(call: Call<Authenticate>, response: Response<Authenticate>) {
(pendingAuthenticateCallbacks.size - 1 downTo 0)
.map { pendingAuthenticateCallbacks.removeAt(it) }
.forEach {
it(Authenticate(httpError = HttpError(
response.code(),
response.errorBody()!!.string()
)))
}
}
})
}
}
}
Inlining inserts the code in the lambda directly into the call site, which removes the overhead of having a function object.
For example, this roughly results in main here:
fun withLambda(lambda: () -> Unit) {
lambda()
}
inline fun inlinedLambda(lambda: () -> Unit) {
lambda()
}
fun main(args: Array<String>) {
withLambda { println("Hello, world") }
inlinedLambda { println("Hello, world") }
}
being converted to this:
fun main(args: Array<String>) {
withLambda { println("Hello, world") }
println("Hello, world") // <- Directly inserted!
}
If you have
pendingAuthenticateCallbacks += callback
This is impossible because callback must be an object in order for it to be added to the list.
You need to add the noinline modifier.
A rough approximation would be to say that an inlined lambda cannot be treated as an object, as it doesn't really exist as an object. It is used directly instead of being created as an object.
Of course, you could create a containing lambda:
pendingAuthenticateCallbacks += { callback() } // Not a good idea
but this would entirely defeat the point of inlining (don't do this!).
However, making the parameter noinline would mean your method now has zero lambda parameters that can be inlined, so you might as well just remove the inline modifier as performance benefit would be minimal.
The compiler should recognize this:
Note that if an inline function has no inlinable function parameters and no reified type parameters, the compiler will issue a warning, since inlining such functions is very unlikely to be beneficial.
The main reason for inlining methods is for performance when using lambdas and for reified generic type parameters. As of Kotlin 1.1, it is also possible to have an inline property accessor for properties without a backing field.
In short, if you have no lambda parameters (or no reified type parameters, in which case you must), it is usually pointless to mark a function as inline.