I was trying to learn higher order functions from the first example of this video. Here's my code and output.
Code
fun lowercase(value: String) = value.toLowerCase()
fun higherOrder(value:String, op: (String) -> String) : String {
println("Executing higher order fun $op")
return op(value)
}
fun main(args: Array<String>) {
println(higherOrder("HELLO", ::lowercase))
println(higherOrder("hello", {it -> lowercase(it)}))
println(higherOrder("HeLlo", { x -> lowercase(x) }))
println(higherOrder("Hello", { lowercase(it) }))
}
Output
Executing higher order fun function lowercase (Kotlin reflection is not available)
hello
Executing higher order fun Function1<java.lang.String, java.lang.String>
hello
Executing higher order fun Function1<java.lang.String, java.lang.String>
hello
Executing higher order fun Function1<java.lang.String, java.lang.String>
hello
Process finished with exit code 0
So my question is, why does it print Kotlin reflection is not available?
Full reflection requires the kotlin-reflect library in addition to kotlin-stdlib.
If full reflection is available it will probably have a more comprehensive toString(), hence the message.
add kotlin-reflect library
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.7.0'
I try it, it works.
Related
I started playing with the new context receivers feature. I intend to use that as a "localized dependency injection" to pass client context around. Currently, I have this (ClientProvider is a fun interface):
fun <T> withClient(client: Client, block: ClientProvider.() -> T) =
ClientProvider { client }.block()
This works pretty well in the production code, e.g. I can do
class MyService {
context(ClientProvider)
fun methodUsingClient() {}
}
However, an issue arises when I want to mockk this code in tests. Currently, I have
val myService: MyService = mockk { every { methodUsingClient() } just runs }
This obviously doesn't work because the ClientProvider context is missing. I would like to fix that by composing mockk and withClient. I imagine it could look like this
inline fun <reified T : Any> mockkWithClient(noinline block: context(T) ClientProvider.() -> Unit) =
mockk<T> { withClient(mockk(), block) }
This indeed works at the call site, i.e., the compiler seems to be happy with
val myService: MyService = mockkWithClient { every { methodUsingClient() } just runs }
but the function itself doesn't compile - the compiler complains about the block parameter:
Type mismatch.
Required:
ClientProvider.() → TypeVariable(T)
Found:
context(T) ClientProvider.() → Unit
Intuitively, I would expect that the extra T context wouldn't harm the block usage inside withClient but apparently, it does.
Is there any way how I can define mockkWithClient so it can be used as outlined above?
I got a useful answer to my other, more generally formulated question, and based on that I was able to solve this problem as well (the key point I was missing is that I have to manually pass the receivers to the block):
inline fun <reified T : Any> mockkWithClient(noinline block: context(ClientProvider) T.() -> Unit) =
withMockClient<T> { mockk { block(this#withMockClient, this#mockk) } }
fun <T> withMockClient(block: ClientProvider.() -> T) =
ClientProvider { mockk() }.block()
The intended usage is then as expected:
mockkWithClient { every { methodUsingClient() }
Note, however, the very specific type of block: it's context(ClientProvider) T.() -> Unit. If I read the documentation correctly I should be also able to write context(ClientProvider, T) () -> Unit but that doesn't compile with the message Subtyping relation between context receivers is prohibited. The root cause of this is still unknown to me but my original problem is solved, nevertheless.
I have a function that compares responses from two different endpoints. It looks like this:
suspend fun <I, T> multiplexOrShadow(
request: I,
v1ResponseStringGenerator: KFunction1<T, String> = ::getV1ResponseString,
v2ResponseStringGenerator: KFunction1<T, String> = ::getV2ResponseString,
) {
<Call two different endpoints for request>
val v1str = v1ResponseStringGenerator(v1Response)
val v2str = v2ResponseStringGenerator(v2Response)
<compare v1str and v2str>
}
As you can see, the caller can pass in the function on how to generate response string from the response of the two endpoints. I also have a default function for the response generators. They look like this:
private fun <T> getV1ResponseString(v1Response: T): String {
return v1Response.toString()
}
private fun <T> getV2ResponseString(v2Response: T): String {
return v2Response.toString()
}
This compiles fine in IntelliJ. However, when I run the gradle build, it fails with the error
Type inference failed: Not enough information to infer parameter T in fun <T> getV1ResponseString(v1Response: T): String
Please specify it explicitly.
What am I doing wrong? I am using Kotlin 1.6.10 in my gradle build.
Looks like this is a known issue, which is fixed since Kotlin 1.6.20: https://youtrack.jetbrains.com/issue/KT-12963.
For Kotlin 1.6.10, the workaround is to avoid using the KFunctionN types if you don't need them. For example, if you only need to invoke a function, it's fine to use just the FunctionN type, also denoted with (...) -> ...:
suspend fun <I, T> multiplexOrShadow(
request: I,
v1ResponseStringGenerator: (T) -> String = ::getV1ResponseString,
v2ResponseStringGenerator: (T) -> String = ::getV2ResponseString,
) {
...
}
what's the difference between this two types of main function in kotlin
fun main(args: Array<String>) {
print("Hello World!")
}
and
fun main() {
print("Hello World!")
}
The syntax with the args is used to pass the parameters to the module from command line interface or from outside program. If you don't need it, you can omit it.
If you are getting started with kotlin I strongly recommend you to look at kotlin official website.
With the first option you could pass arguments when running your program
I'm new to Kotlin's Arrow Framework and I have a couple of questions:
Lets suppose
fun getUser(id: Int): IO<Option<User>>
fun getCards(user: User): IO<List<Card>>
fun getUserAndCards(id: Int): IO<Option<Pair<User, List<Card>>>> = IO.fx {
when (val user = !userRepository.get(id)) {
is None -> None
is Some -> {
val cards = !cardRepository.get(user.t.id)
Some(Pair(user.t, cards))
}
}
}
How can I achieve the same functionality in an "arrow stylish" manner?
I manage to get:
fun getUserAndCards(id: Int): IO<Option<Pair<User, List<Card>>>> = IO.fx {
userRepository.get(id).bind().map { user ->
val cards = cardRepository.get(user.id).bind()
Pair(user, cards)
}
}
But I obtain Suspension functions can be called only within coroutine body in the second bind().
EDIT:
I saw this post with the same question. In the answer provided, it says The problem is that the left/none option isn't covered. But IT IS covered, when applying map to a None it is expected to obtain a None.
With the new 0.11.0 release coming up soon, the most idiomatic way would be to use Arrow Fx Coroutines.
Rewriting the example to Arrow Fx Coroutines would be:
suspend fun getUser(id: Int): Option<User>
suspend fun getCards(user: User): List<Card>
suspend fun getUserAndCards(id: Int): Option<Pair<User, List<Card>>> =
option {
val user = !userRepository.get(id)
val cards = !cardRepository.get(user.t.id)
Pair(user.t, cards)
}
Where you can now rely on a option { } DSL to extract the values from Option.
The problem is that the left/none option isn't covered. But IT IS covered, when applying map to a None it is expected to obtain a None.
You're correct that it's covered, but ! is a suspending function, and map is currently not inlined so you're not allowed to call ! inside. In the 0.11.0 release the operators from the data types in Arrow-Core are inline, to improve support for suspend functions and this would solve the Suspension functions can be called only within coroutine body error.
In other functional languages such as Haskell monad transformers are often used (OptionT), but in Kotlin using suspend is a much better fit which also has quite some performance benefits over wrapping monad transfomers.
As mentioned in the other post, you can also always use traverse or sequence to turn two containers around. Option<IO<User>> -> IO<Option<User>>
I get an overall idea of what is each of these, I wrote piece of code however that I don't quite understand why it works.The thing is callExtensionOnString expects extension function as its parameter, however it doesn't complain if reference to printString is passed.
Is String.() -> Unit just another name for (String) -> Unit type or is it Kotlin compiler that takes some kind of shortcut to fit higher order in extension function?
fun main(args: Array<String>) {
callExtensionOnString(::printString)
}
fun callExtensionOnString(extensionFun: String.() -> Unit) {
"testString".extensionFun()
}
fun printString(str: String) {
println(str)
}
Then there is second thing that seems unclear to me. printString reference is passed once to callExtensionOnString and then again to run function which basically requires String.() -> Unit extension function. Is there difference between these two so that second time :: prefix is omitted?
fun main(args: Array<String>) {
runFunctionOnString(::printString)
}
fun runFunctionOnString(higherOrderFun: (String) -> Unit) {
"testString".run(higherOrderFun)
}
fun printString(str: String) {
println(str)
}
Concerning your first question, these 2 are equivalent:
"testString".extensionFun()
extensionFun("testString")
That's why passing printString method doesn't cause a compilation error.
Concerning the second question, the difference is that highOrderFun is already a reference to a function, while printString is not a function reference (but you can obtain it with the :: operator)