How to inform in Kotlin that a function passed by parameter can throw an exception? - kotlin

I need to inform in my class code that the function passed by parameter (convertorCall) can throw an exception.
suspend operator fun <T> invoke(
convertorCall: () -> T
): T?
For example, if this function were as a method of a class I could do this:
#Throws(JsonSyntaxException::class)
suspend fun <T> convertorCall(): T
However, as said before, I need this to be informed in the function passed by parameter of the invoke function.
I tried this:
suspend operator fun <T> invoke(
#Throws(JsonSyntaxException::class) convertorCall: () -> T
): T?
But a syntax error is generated:
This annotation is not applicable to target 'value parameter'

Kotlin doesn't have checked exceptions, i.e. ones where a function explicitly states what it could throw, and any callers are required to wrap the call in a try/catch to deal with that possibility. Or not catch it, state that they themselves might produce that exception, and pass the responsibility to handle it up the chain.
That link explains the rationale, and links to some sources talking about the issue, but it's basically just how things are done (or not done) in Kotlin. There's a #Throws annotation for interoperability with other languages where checked exceptions is how things are done, but it's not used in Kotlin itself.
If you want to inform the caller that an exception could be thrown, you're supposed to put it in the documentation comment for the function. There's a #throws tag (or an #exception one if you like) for that purpose, but like it says:
Documents an exception which can be thrown by a method. Since Kotlin does not have checked exceptions, there is also no expectation that all possible exceptions are documented, but you can still use this tag when it provides useful information for users of the class.
So it's purely informational really, and the user can choose to handle or not handle those potential exceptions - it's not required. And if you're writing your own functions, you might want to consider whether they should throw an exception to the caller at all during normal, anticipated behaviour, or if they should return some kind of error value (like null) or an error type (e.g. a sealed class that has some kind of failure subclass as well as success types).
// You could return this type instead of throwing an exception
sealed class Result<T> {
class Conversion<T>(data: T) : Result<T>()
class Error<T>(message: String) : Result<T>()
}
Basically, if you know a specific thing can go wrong during normal operation, is it really exceptional? Or just another kind of result to inform the caller about so it can take action if it needs to?

Related

Why is var or val not allowed in a functions' parameter in kotlin?

fun myfunction(a:String) //this is valid
fun myfunction(var a:String) //this is invalid
fun myfunction(val a:String) //this is invalid
The support for var was removed way back from kotlin with the following reason:
The main reason is that this was confusing: people tend to think that this means passing a parameter by reference, which we do not support (it is costly at runtime). Another source of confusion is primary constructors: “val” or “var” in a constructor declaration means something different from the same thing if a function declarations (namely, it creates a property). Also, we all know that mutating parameters is no good style, so writing “val” or “var” infront of a parameter in a function, catch block of for-loop is no longer allowed.
More details in https://blog.jetbrains.com/kotlin/2013/02/kotlin-m5-1/.

Kotlin compiler shows compilation error and suggests to "change type from 'T' to 'T"' while there is only one T in the context

I tried to implement some type classes from Haskell but confronted the issue that is probably a bug in the Kotlin compiler.
interface Semigroup<Instance> {
infix fun Instance.assocOp(oother: Instance): Instance
}
inline fun <reified T: Semigroup<T>> Iterable<T>.concat() = this.reduce<T, T> { acc: T, t: T -> acc.assocOp(t) }
The error message is "Expected parameter of type T".
IDEA suggests to "Change type from 'T' to 'T'" (does nothing).
I expect acc to belong to the type T mentioned in generics. But because of some reason compiler tries to find some other type T. I tried to
specify the type explicitly/implicitly
build ignoring IDEA message
change used version of Kotlin compiler (I have tried 1.4.20, 1.4.10, 1.3.72).
Nothing worked.
I suppose that writing the function without reduce (manually) may help to deal with it. Also, writing java code doing the same may help to mitigate the problem. But these solutions are only workarounds for the problem. Is the issue my fault or the compiler bug?
The compiler error clearly is not helpful here. However, it is correct that the code should not compile IMO.
You're defining the method assocOp as a member extension function. The extension applies to any type T, but it's a member of the interface Semigroup<T>.
To call that extension, you need both a receiver or type T and a receiver of type Semigroup<T> (acting as a context).
In your case, the type T both plays the role of the generic type parameter and of the Semigroup<T>, but you still need to have 2 "receivers" for your extension, even if both are the same instance.
Maybe try this:
inline fun <reified T : Semigroup<T>> Iterable<T>.concat(): T =
reduce<T, T> { t1: T, t2: T -> with(t1) { t1.assocOp(t2) } }
The with(t1) { ... } provides a context of type Semigroup<T>, while the t1 used in t1.assocOp(t2) acts as the T receiver.

In RxJava/RxKotlin, what are the differences between returning a Completable.error(Exception()) and throwing?

What are the differences in the following cases:
fun a(params: String) = Completable.fromAction {
if (params.isEmpty()) {
throw EmptyRequiredFieldException()
}
}
VS
fun b(params: String) = if(params.isEmpty())
Completable.error(EmptyRequiredFieldException())
else
Completable.complete()
Specifically in the context of android, if it matters (even though I don't think it does)
Thanks!
According to documentation,
If the Action throws an exception, the respective Throwable is delivered to the downstream via CompletableObserver.onError(Throwable), except when the downstream has disposed this Completable source. In this latter case, the Throwable is delivered to the global error handler via RxJavaPlugins.onError(Throwable) as an UndeliverableException.
So both of two ways you described are similar (except when the downstream has disposed). Note, that first approach (with manually throwing exception) allow to modify behavior of Completable at runtime. And second one - statically defined as you return particular type of Completable and can't modify it.
What to choose depends on your needs.

Why is it impossible to use method references to `suspend` functions in Kotlin?

I have a list of Job instances which I want to cancel at some point after launch. This looks as follows:
val jobs = arrayListOf<Job>()
//launch and add jobs...
jobs.forEach { it.cancelAndJoin() } // cancels the jobs and waits for completion
Unfortunately, it's not possible to use a method reference here. The reason: cancelAndJoin is a suspend function, as the compiler complains:
jobs.forEach (Job::cancelAndJoin)
"Error:(30, 24) Kotlin: Unsupported [Callable references to suspend functions]"
Why doesn't this work?
UPD: This has already been implemented in Kotlin 1.3.x. Taking a callable reference to a suspending function gives you an instance of KSuspendFunctionN (N = 0, 1, ...). This type has its invoke operator defined as a suspending function, so that you can invoke such a callable reference suspending a coroutine in the same way as a direct invocation would.
Basically, supporting this requires an additional portion of language design and does not simply come bundled with coroutines.
Why is it non-trivial? Because when you take a callable reference of an ordinary function e.g. String::reversed, you get something like a KFunction1<String, String>. If you could do the same with a suspend function, what would you expect to get?
If it's the same KFunctionN<...>, then there's an obvious problem that you can pass it around where an ordinary function is expected and call it, violating the rule that suspend functions can only be called inside coroutines (where the compiler transforms their call sites).
So, it should be something more specific. (I'm currently only speculating, without any idea of actual design attempts) It could be, for example, a SuspendKFunctionN<...>, with its invoke(...) being a suspending function, or it could (less likely) be a special notation only for passing a function reference where a suspend (T) -> R is expected, but anyway, a feature like this requires thorough design to be future-proof.
These helpers currently lack in Kotlin Standard library, but you can implement your own.
For example:
suspend fun <T> Iterable<T>.forEachAsync(action: suspend (T) -> Unit): Unit {
val list = this.map { e ->
async(...) {
action(e)
}
}
list.forEach { it.await() }
}
However, what context to pass to async now depends on the threading model your service is using (i.e. do you want to do multi-threading or want to keep everything in a single thread).

Usage of CompletableFuture's exceptionally method in Kotlin

I'm trying to handle CompletableFuture exceptions in Kotlin, but I'm not able to figure out how to supply the appropriate parameters. So, for example, I have:
CompletableFuture.runAsync { "sr" }
.exceptionally{e -> {}}
but then the compiler complains Cannot infer type parameter T.
How do I fix this?
Quite a tricky case which becomes tricky because of some Kotlin magic :)
The direct solution to your problem would be the following code:
CompletableFuture.runAsync {"sr"}
.exceptionally({e -> null})
The detailed explanation goes here:
The runAsync method accepts a Runnable which means after execution it will return Void. The function passed to exceptionally method must match the generic parameter of the CompletableFuture so in this particular case, you need to help a compiler by returning null explicitly.
So the following will compile without problems:
CompletableFuture.runAsync {"sr"}
.exceptionally({null})
CompletableFuture.runAsync {}
.exceptionally({null})
In the first case, the "sr" String will simply be ignored and not returned since the runAsync accepts a Runnable.
You probably wanted to do something like:
CompletableFuture.supplyAsync {"sr"}
.exceptionally({"sr_exceptional"})
or:
CompletableFuture.supplyAsync {"sr"}
.exceptionally({e -> "sr_exceptional"})