How to resolve "Not enough information to infer type variable" when one type variable not inferrable AND using wildcard on the other? - kotlin

Trying to convert some Java code to Kotlin, the Java code includes a call to a library method TableUtils.dropTable which is implemented in Java. The Java method signature of this method is
public static <T, ID> int dropTable(ConnectionSource connectionSource, Class<T> dataClass, boolean ignoreErrors) throws SQLException
When calling the method from Java it compiles fine even though the type variable ID is not known. For example:
public void method(ConnectionSource connectionSource, Class<? extends IRecordObject> clazz) {
try {
TableUtils.dropTable(connectionSource, clazz, true); // this compiles fine
} catch (SQLException e) {
e.printStackTrace();
}
}
After converting to Kotlin, the corresponding function fails to compile because the type variable ID cannot be inferred:
fun method(connectionSource: ConnectionSource?, clazz: Class<out IRecordObject>) {
try {
TableUtils.dropTable(connectionSource, clazz, true) // compile error: "Not enough information to infer type variable ID"
} catch (e: SQLException) {
e.printStackTrace()
}
}
I don't know how I can explicitly specify the type variables, as one of them would be a wildcard, and you aren't allowed to use wildcards in type variables when calling functions. For example:
TableUtils.dropTable<out IRecordObject,Long>(connectionSource, clazz, true) // this also fails to compile, "Projections are not allowed on type arguments of functions and properties"
So how can I specify the type variable ID here to allow the code to compile in Kotlin?

The type ID is unused in the function signature, so it doesn't matter what it is. For the Kotlin version, you can literally put any type there to make the error go away. Whichever type you use will have no effect on the compiled code because of type erasure. You can use an underscore to allow T to be inferred.
fun method(connectionSource: ConnectionSource?, clazz: Class<out IRecordObject>) {
try {
TableUtils.dropTable<_, Unit>(connectionSource, clazz, true)
} catch (e: SQLException) {
e.printStackTrace()
}
}
I actually don't know how you can write out the type and make it work instead of using inference. The only way I can think to make it work is to make this function generic so you can use an invariant Class type:
fun <T: IRecordObject> method(clazz: Class<T>) {
JavaFoo.dropTable<T, Unit>(clazz, true)
}
I think the Java method signature should have used Class<? extends T> for more proper flexibility and probably should have omitted ID since it is effectively useless.

Related

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")
}

Is there a way to cast from 'String' to 'KType'?

Simply, I want a function like:
fun <T> convert(val foo: String, fooT: KType) : T {
...?
}
For Int, it would return foo.toInt(), for Double, foo.toDouble(), and to some unknown type, just throw an exception. I think it's not so hard to create my own switch statement for the types I expect, but out of curiosity - is there a way already?
Recommended way
Unfortunately, there's no easy generic way because we're not dealing with casts, but method calls. This would be my approach:
fun <T> convert(str: String, type: KType) : T {
val result: Any = when (type.jvmErasure)
{
Long::class -> str.toLong()
Int::class -> str.toInt()
Short::class -> str.toShort()
Byte::class -> str.toByte()
...
else -> throw IllegalArgumentException("'$str' cannot be converted to $type")
}
return result as T // unchecked cast, but we know better than compiler
}
Usage:
#UseExperimental(ExperimentalStdlibApi::class)
fun main() {
val int = convert<Int>("32", typeOf<Int>())
println("converted: $int")
}
Instead of a KType parameter, you could also use a Class<T> and make the function reified, so it can be called as convert<Int>("32") or even "32".toGeneric<Int>().
Hardcore way
While there is no easy way, it is possible to access the type using heavy reflection and relying on implementation details. For this, we can extract the type name from the KType object, find an extension method (in a different class) that matches, and call it using reflection.
We have to use to*OrNull() instead of to*(), because the latter is inline and won't be found by reflection. Also, we need to resort to Java reflection -- at this time, Kotlin reflection throws UnsupportedOperationException for the types involved.
I do not recommend this in productive code, as it's inefficient and can break with future standard library versions, but it's a nice experiment:
fun convert(str: String, type: KType): Any {
val conversionClass = Class.forName("kotlin.text.StringsKt")
// here, the to*OrNull() methods are stored
// we effectively look for static method StringsKt.to*OrNull(String)
val typeName = type.jvmErasure.simpleName
val funcName = "to${typeName}OrNull" // those are not inline
val func = try {
conversionClass.getMethod(funcName, String::class.java) // Java lookup
} catch (e: NoSuchMethodException) {
throw IllegalArgumentException("Type $type is not a valid string conversion target")
}
func.isAccessible = true // make sure we can call it
return func.invoke(null, str) // call it (null -> static method)
?: throw IllegalArgumentException("'$str' cannot be parsed to type $type")
}

Kotlin Vertx Type Mismatch found Future<Unit> expected Handler<AsyncResult<Void>>

I thought that in Kotlin, Unit was equivalent to Void. With Vert.x Service Discovery, it is not possible to pass a Future<Unit> to unpublish(String id, Handler<AsyncResult<Void>> resultHandler) (gives a type mismatch) yet it will accept Future<Void> without any problem. Why is this and is there a solution or will I just have to live with using Void?
Unit is not equivalent to Void, it is equivalent to void in kotlin.
In java, void is a keyword, but Void is a class. so the code below can't be compiled:
fun foo():Void{/**need return a Void instance exactly**/}
fun bar():Void{ return Unit; }
// ^--- type mismatch error
java applies the same rule, for example:
Void canNotBeCompiled(){
// must return a Void instance exactly.
}
Void foo(){
return Void.TYPE;
}
Void nil(){
return null;
}
Finally the Unit documentation also says:
The type with only one value: the Unit object. This type corresponds to the void type in Java.

Call Kotlin inline function from Java

Exceptions.kt:
#Suppress("NOTHING_TO_INLINE")
inline fun generateStyleNotCorrectException(key: String, value: String) =
AOPException(key + " = " + value)
In kotlin:
fun inKotlin(key: String, value: String) {
throw generateStyleNotCorrectException(key, value) }
It works in kotlin and the function is inlined.
But when used in Java code, It just cannot be inlined,
and still a normal static method call (seen from the decompiled contents).
Something like this:
public static final void inJava(String key, String value) throws AOPException {
throw ExceptionsKt.generateStyleNotCorrectException(key, value);
// when decompiled, it has the same contents as before , not the inlined contents.
}
The inlining that's done by the Kotlin compiler is not supported for Java files, since the Java compiler is unaware of this transformation (see this answer about why reified generics do not work from Java at all).
As for other use cases of inlining (most commonly when passing in a lambda as a parameter), as you've already discovered, the bytecode includes a public static method so that the inline function can be still called from Java. In this case, however, no inlining occurs.
Yes, u can do it
In Kotlin file:
Builder.sendEvent { event ->
YandexMetrica.reportEvent(event)
}
.build();
In Java file:
Builder.sendEvent(new Function1<String, Unit>() {
#Override
public Unit invoke(String event) {
Log.i("TEST", event);
return null;
}
})
.build();

Try-with-resources in Kotlin

When I tried to write an equivalent of a Java try-with-resources statement in Kotlin, it didn't work for me.
I tried different variations of the following:
try (writer = OutputStreamWriter(r.getOutputStream())) {
// ...
}
But neither works. Does anyone know what should be used instead?
Apparently Kotlin grammar doesn't include such a construct, but maybe I'm missing something. It defines the grammar for a try block as follows:
try : "try" block catchBlock* finallyBlock?;
There is a use function in kotlin-stdlib (src).
How to use it:
OutputStreamWriter(r.getOutputStream()).use {
// `it` is your OutputStreamWriter
it.write('a')
}
TL;DR: No special syntax, just a function
Kotlin, as opposed to Java, does not have a special syntax for this. Instead, try-with-resources, is offered as the standard library function use.
FileInputStream("filename").use { fis -> //or implicit `it`
//use stream here
}
The use implementations
#InlineOnly
public inline fun <T : Closeable?, R> T.use(block: (T) -> R): R {
var closed = false
try {
return block(this)
} catch (e: Exception) {
closed = true
try {
this?.close()
} catch (closeException: Exception) {
}
throw e
} finally {
if (!closed) {
this?.close()
}
}
}
This function is defined as a generic extension on all Closeable? types. Closeable is Java's interface that allows try-with-resources as of Java SE7.
The function takes a function literal block which gets executed in a try. Same as with try-with-resources in Java, the Closeable gets closed in a finally.
Also failures happening inside block lead to close executions, where possible exceptions are literally "suppressed" by just ignoring them. This is different from try-with-resources, because such exceptions can be requested in Java‘s solution.
How to use it
The use extension is available on any Closeable type, i.e. streams, readers and so on.
FileInputStream("filename").use {
//use your stream by referring to `it` or explicitly give a name.
}
The part in curly brackets is what becomes block in use (a lambda is passed as an argument here). After the block is done, you can be sure that FileInputStream has been closed.
Edit: The following response is still valid for Kotlin 1.0.x. For Kotlin 1.1, there is support a standard library that targets Java 8 to support closable resource pattern.
For other classes that do not support the "use" function, I have done the following homemade try-with-resources:
package info.macias.kotlin
inline fun <T:AutoCloseable,R> trywr(closeable: T, block: (T) -> R): R {
try {
return block(closeable);
} finally {
closeable.close()
}
}
Then you can use it the following way:
fun countEvents(sc: EventSearchCriteria?): Long {
return trywr(connection.prepareStatement("SELECT COUNT(*) FROM event")) {
var rs = it.executeQuery()
rs.next()
rs.getLong(1)
}
}
I will highly recommend to use AutoCloseable for classes.
AutoCloseable object is called automatically when exiting a
try-with-resources block for which the object has been declared in the
resource specification header.
Example:
class Resource : AutoCloseable {
fun op1() = println("op1")
override fun close() = println("close up.")
}
in main function:
Resource().use {
it.op1()
}
Output:
> op1
close up.
Since this StackOverflow post is near the top of the current search results for "kotlin closeable example," and yet none of the other answers (nor the official docs) clearly explain how to extend Closeable (a.k.a. java.io.Closeable), I thought I'd add an example of how to make your own class that extends Closeable. It goes like this:
import java.io.Closeable
class MyServer : Closeable {
override fun close() {
println("hello world")
}
}
And then to use it:
fun main() {
val s = MyServer()
s.use {
println("begin")
}
println("end")
}
See this example in the Kotlin Playground here.