Type mismatch on throw line in Kotlin? - kotlin

Please help me understand the following error in Kotlin: I have the following function
fun getSomething(): Something {
return loginContext.user()?.let {
// user is logged in
return Something()
} ?: {
// user is not logged in
throw UnauthorizedException()
}
}
and IntelliJ tells me
Type mismatch.
Required: Something
Found: () → Nothing
Coming from Java I find this a bit confusing because when I throw an exception there is nothing to return. How can there be a type mismatch?

I believe you may write it like this (using expression body)
fun getSomething(): Something = loginContext.user()
?.let { Something() }
?: throw UnauthorizedException()

Related

How to convert kotlin Result type from List<Result<T>> to Result<List<T>>

I have List<Result<String>> and I would like to convert it to Result<List<String>>. I understand that List<Result<String>> could have both failure and successful results but I would like to terminate in the first failure.
If you want to have a failure as soon there is one Result that is a failure you can do this :
fun <T> List<Result<T>>.toResult() = if (any { it.isFailure }) {
Result.failure<List<Result<Any>>>(Throwable("A result has errors"))
} else {
Result.success(map { it.getOrNull() })
}
With this code, you get a failure as soon as there is one value has a failure.
Or if you don't care handling the error yourself :
fun <T> List<Result<T>>.toResult() = runCatching {
Result.success(map { it.getOrThrow() })
}
In most libraries this function is known as sequence.
Kotlin's Arrow library implements it for its implementation of the type Either, which is a generalization of Result: https://arrow-kt.io/docs/apidocs/arrow-core/arrow.core/sequence.html
With Arrow's Either you would write:
val xs: List<Result<String>> = ...
val ys: Result<List<String>> = xs.sequence()
The Kotlin stdlib does not seem to have it. You could define it as an extension method using getOrThrow, catching any thrown Throwable and wrapping in a Resultagain:
fun <T> List<Result<T>>.sequence(): Result<List<T>> = try {
Result.success(this.map { it.getOrThrow() })
}
catch (e:Throwable) { Result.failure(e) }

Undetected throw declaration (Kotlin)

Let's have a function which just computes something in try-catch and returns the result:
private fun compute(): String {
return try {
// do some computation
// ...
"result"
} catch(t: Throwable) {
throw RuntimeException("Uups") // <-- GOAL: extract this to a dedicated method
}
}
I would like to extract the throw declaration to a separate function (which contains the my boilerplate code).
However, I'm unable to compile such setup in Kotlin.
A simplistic (and still uncompilable) version of the described problem:
private fun compute(): String {
return try {
// do some computation
// ...
"result"
} catch(t: Throwable) {
justThrow() // <-- NOT COMPILABLE, STRING EXPECTED
}
}
#Throws(RuntimeException::class)
private fun justThrow() {
// some boilerplate code
// ...
throw RuntimeException("Uups")
}
How write justThrow() method in Kotlin so that the whole code is compilable?
In Java this case would be detected by a compiler (I suppose).
Kotlin version: 1.4.21
You can declare the return type of your method as Nothing. This type can be used for any method that does not return normally. That might be because it will always throw an exception, or simply never returns at all, for instance because it contains an infinite loop.
private fun justThrow(): Nothing {
// some boilerplate code
// ...
throw RuntimeException("Uups")
}

Functional (Result / Error) translation using Kotlin runCatching

I am trying to use Kotlin runCatching feature along with response + error translation functions. Something like
class SomeClassThatCallsServiceX {
fun remoteCall(input): TransformedResult {
kotlin.runCatching{ serviceX.call(input)}
.onSuccess { return functionToTranslateServiceXResponse(it)}
.onFailure{ throw functionToranslateServiceXError(it)}
}
}
functionToTranslateServiceXResponse : (OriginalResult) -> TransformedResult
functionToranslateServiceXError : (Throwable) -> RuntimeException
However Kotlin is giving me the following error - A 'return' expression required in a function with a block body ('{...}'). If you got this error after the compiler update, then it's most likely due to a fix of a bug introduced in 1.3.0 (see KT-28061 for details)
Running with Kotlin 1.4.
I am still new to Kotlin- wondering if I am doing something fundamentally wrong here. Any help would be greatly appreciated.
Update: tried the following pattern, basic test cases seem to be working fine. Would love to know what others think of the pattern
class SomeClassThatCallsServiceX {
fun remoteCall(input): TransformedResult {
return kotlin.runCatching{ serviceX.call(input)}
.mapCatching(functionToTranslateServiceXResponse)
.onFailure(functionToranslateServiceXError)
.getOrThrow()
}
}
functionToTranslateServiceXResponse : (OriginalResult) -> TransformedResult
functionToranslateServiceXError : (Throwable) -> Unit
I think there are couple of issues here:
class SomeClassThatCallsServiceX {
// You are not returning `TransformedResult` but Result<TransformedResult>
// but Result cannot be returned by kotlin https://stackoverflow.com/q/52631827/906265
fun remoteCall(input) {
// error mentioned that "return" was missing but you cannot return Result
kotlin.runCatching{ serviceX.call(input)}
.onSuccess { return functionToTranslateServiceXResponse(it) }
.onFailure{ throw functionToranslateServiceXError(it) }
}
}
Having a callback could be a solution (pseudocode):
fun remoteCall(input Any, callback: Callback) {
kotlin.runCatching{ serviceX.call(input)}
.onSuccess { callback.success(it) }
.onFailure { callback.error(it) }
}
Have a tiny example on Kotlin Playground website based on the above https://pl.kotl.in/W8wMDEzN1

Kotlin case of non-intuitive type inference

I found some non-intuitive behavior of type inference. As a result, the semantically equivalent code works differently, depending on what information the compiler infers about function return type. It is more or less clear what is going on when you reproduce this case in a minimum unit test. But I afraid that when writing framework code, such behavior could be dangerous.
The code below illustrates the problem, and my questions are:
Why the puzzler1 call from notok1 unconditionally throws NPE? As far as I understand from the bytecode, ACONST_NULL ATHROW throws NPE right after puzzler1 call, ignoring the returned value.
Is it normal that upper bound (<T : TestData>) is ignored when compiler infers the type?
Is it a bug that NPE becomes ClassCastException if you add suspend modifier to the function? Of course, I understand that runBlocking+suspend call gives us the different bytecode, but shouldn't the "coroutinized" code be as equivalent as possible to conventional code?
Is there a way to rewrite puzzler1 code somehow, eliminating the unclearness?
#Suppress("UnnecessaryVariable", "MemberVisibilityCanBePrivate", "UNCHECKED_CAST", "RedundantSuspendModifier")
class PuzzlerTest {
open class TestData(val value: String)
lateinit var whiteboxResult: TestData
fun <T : TestData> puzzler1(
resultWrapper: (String) -> T
): T {
val result = try {
resultWrapper("hello")
} catch (t: Throwable) {
TestData(t.message!!) as T
}
whiteboxResult = result
return result // will always return TestData type
}
// When the type of `puzzler1` is inferred to TestData, the code works as expected:
#Test
fun ok() {
val a = puzzler1 { TestData("$it world") }
// the same result inside `puzzler1` and outside of it:
assertEquals("hello world", whiteboxResult.value)
assertEquals("hello world", a.value)
}
// But when the type of `puzzler1` is not inferred to TestData, the result is rather unexpected.
// And compiler ignores the upper bound <T : TestData>:
#Test
fun notok1() {
val a = try {
puzzler1 { throw RuntimeException("goodbye") }
} catch (t: Throwable) {
t
}
assertEquals("goodbye", whiteboxResult.value)
assertTrue(a is NullPointerException) // this is strange
}
// The same code as above, but with enough information for the compiler to infer the type:
#Test
fun notok2() {
val a = puzzler1 {
#Suppress("ConstantConditionIf")
if (true)
throw RuntimeException("goodbye")
else {
// the type is inferred from here
TestData("unreachable")
// The same result if we write:
// puzzler1<TestData> { throw RuntimeException("goodbye") }
}
}
assertEquals("goodbye", whiteboxResult.value)
assertEquals("goodbye", (a as? TestData)?.value) // this is stranger
}
// Now create the `puzzler2` which only difference from `puzzler1` is `suspend` modifier:
suspend fun <T : TestData> puzzler2(
resultWrapper: (String) -> T
): T {
val result = try {
resultWrapper("hello")
} catch (t: Throwable) {
TestData(t.message!!) as T
}
whiteboxResult = result
return result
}
// Do exactly the same test as `notok1` and NullPointerException magically becomes ClassCastException:
#Test
fun notok3() = runBlocking {
val a = try {
puzzler2 { throw RuntimeException("goodbye") }
} catch (t: Throwable) {
t
}
assertEquals("goodbye", whiteboxResult.value)
assertTrue(a is ClassCastException) // change to coroutines and NullPointerException becomes ClassCastException
}
// The "fix" is the same as `notok2` by providing the compiler with info to infer `puzzler2` return type:
#Test
fun notok4() = runBlocking {
val a = try {
puzzler2<TestData> { throw RuntimeException("goodbye") }
// The same result if we write:
// puzzler2 {
// #Suppress("ConstantConditionIf")
// if (true)
// throw RuntimeException("goodbye")
// else
// TestData("unreachable")
// }
} catch (t: Throwable) {
t
}
assertEquals("goodbye", whiteboxResult.value)
assertEquals("goodbye", (a as? TestData)?.value)
}
}
What is the type of throw RuntimeException("goodbye")? Well, since it never returns a value, you can use it anywhere you like, no matter what type of object is expected, and it will always typecheck. We say that it has type Nothing. This type has no values, and it is a subtype of every type. Therefore, in notok1, you have a call to puzzler1<Nothing>. The cast from the constructed TestData to T = Nothing inside puzzler1<Nothing> is unsound but unchecked, and puzzler1 ends up returning when its type signature says it shouldn't be able to. notok1 notices that puzzler1 has returned when it said it would not be able to, and immediately throws an exception itself. It's not very descriptive, but I believe the reason it throws an NPE is because something has gone "terribly wrong" if a function that can't return has returned, so the language decides the program should die as fast as possible.
For notok2, you actually do get T = TestData: one branch of the if returns Nothing, the other TestData, and the LUB of those is TestData (since Nothing is a subtype of TestData). notok2 has no reason to believe that puzzler1<TestData> cannot return, so it doesn't set up the trap to die as soon as puzzler1 returns.
notok3 has essentially the same problem as notok1. The return type, Nothing, implies that the only thing the puzzler2<Nothing> will do is throw an exception. The coroutine handling code in notok3 thus expects the coroutine to hold a Throwable and contains code to rethrow it, but does not contain code to handle an actual return value. When puzzler2 actually does return, notok3 tries to cast that TestData into a Throwable and fails. notok4 works for the same reason notok2 does.
The solution to this mess is simply not using an unsound cast. Sometimes puzzler1<T>/puzzler2<T> will be able to return a T, if the passed function in fact returns a T. But, if that function throws, they can only return a TestData, and a TestData is not a T (a T is a TestData, not the other way around). The correct signature for puzzler1 (and similarly for puzzler2) is
fun <T : TestData> puzzler1(resultWrapper: (String) -> T): TestData
Since functions are covariant in the return type, you can just get rid of the type parameter
fun puzzler1(resultWrapper: (String) -> TestData): TestData

UninferredParameterTypeConstructor exception during build when generic parameters not specified explicitly

I have the following code (using RxKotlin 0.40.1):
class Result<T, E>(val data: T? = null, val error: E? = null)
fun <T, E> wrapResult(errorInfoFactory: (Throwable) -> E): (Observable<T>) -> Observable<Result<T, E>> = { it.map { Result<T, E>(it) }.onErrorReturn { Result<T, E>(error = errorInfoFactory(it)) } }
Just FYI this is needed to easily transform Observable which may throw errors to an Observable which always returns Result object, so onError is never triggered.
And I want to use it like this:
fun dangerousOperation() = 0
fun getErrorMessage(t: Throwable) = "error occurred"
fun test() {
val resultObservable = Observable.fromCallable(::dangerousOperation).compose(wrapResult(::getErrorMessage))
}
And Android Studio 1.5.1 with Kotlin plugin 1.0.0-release-IJ141-56 doesn't highlight any errors in this code. But when I try to build it, I get the error:
//Error:(24, 9) org.jetbrains.kotlin.codegen.CompilationException:
Back-end (JVM) Internal error: Error type encountered:
org.jetbrains.kotlin.types.ErrorUtils$UninferredParameterTypeConstructor#68754e6
(ErrorTypeImpl). //Cause: Error type encountered:
org.jetbrains.kotlin.types.ErrorUtils$UninferredParameterTypeConstructor#68754e6
(ErrorTypeImpl). //File being compiled and position: (24,9) in
/home/d/work/workspace/Hitch-hiking-Stats/app/src/main/java/ru/netimen/hitch_hikingstats/MemoryRepo.kt
//PsiElement: val resultObservable =
Observable.just(dangerousOperation()).compose(wrapResult(::getErrorMessage))
//The root cause was thrown at: JetTypeMapper.java:435 // at
org.jetbrains.kotlin.codegen.ExpressionCodegen.genQualified(ExpressionCodegen.java:299)
// at
org.jetbrains.kotlin.codegen.ExpressionCodegen.genStatement(ExpressionCodegen.java:339)
// at
org.jetbrains.kotlin.codegen.ExpressionCodegen.generateBlock(ExpressionCodegen.java:1532)
// at
org.jetbrains.kotlin.codegen.ExpressionCodegen.generateBlock(ExpressionCodegen.java:1485)
// at
org.jetbrains.kotlin.codegen.CodegenStatementVisitor.visitBlockExpression(CodegenStatementVisitor.java:56)
// at
org.jetbrains.kotlin.codegen.CodegenStatementVisitor.visitBlockExpression(CodegenStatementVisitor.java:22)
// at
org.jetbrains.kotlin.psi.KtBlockExpression.accept(KtBlockExpression.java:44)
// at
org.jetbrains.kotlin.codegen.ExpressionCodegen.genQualified(ExpressionCodegen.java:280)
// at
org.jetbrains.kotlin.codegen.ExpressionCodegen.genStatement(ExpressionCodegen.java:339)
// at
org.jetbrains.kotlin.codegen.ExpressionCodegen.gen(ExpressionCodegen.java:309)
// at
org.jetbrains.kotlin.codegen.ExpressionCodegen.returnExpression(ExpressionCodegen.java:1873)
// at
org.jetbrains.kotlin.codegen.FunctionGenerationStrategy$FunctionDefault.doGenerateBody(FunctionGenerationStrategy.java:50)
// at
org.jetbrains.kotlin.codegen.FunctionGenerationStrategy$CodegenBased.generateBody(FunctionGenerationStrategy.java:72)
// at
org.jetbrains.kotlin.codegen.FunctionCodegen.generateMethodBody(FunctionCodegen.java:364)
// at
org.jetbrains.kotlin.codegen.FunctionCodegen.generateMethod(FunctionCodegen.java:203)
// at
org.jetbrains.kotlin.codegen.FunctionCodegen.generateMethod(FunctionCodegen.java:138)
But when I change my test function to
fun test() {
val resultObservable = Observable.fromCallable(::dangerousOperation).compose(wrapResult<Int, String>(::getErrorMessage))
}
everything compiles OK. But why I get that exception when I don't specify the generic parameters of wrapResult explicitly if the IDE doesn't highlight any errors?
It is compiler bug: https://youtrack.jetbrains.com/issue/KT-11144.
Main reason why this bug is appear: function wrapResult uses generic parameter T only in own return type.