I am facing some issue trying to port a part of my code to Kotlin. I will give a simplified version of the issue I am facing.
In Java, I can write this code which runs successfully (with compiler warning obviously) -
public interface MyException<T extends Exception> {
void print(T ex);
}
public class MyRuntimeEx implements MyException<RuntimeException> {
public void print(RuntimeException ex) {
System.out.println(ex);
}
}
public static void main(String[] args) {
for (MyException exception : ServiceLoader.load(MyException.class)) {
exception.print(new RuntimeException()); // Compiler warning, but runs successfully
}
}
However, when I try writing the same in Kotlin, that compiler warning turns into an error and I cannot proceed with the code.
interface MyException<T : Exception> {
fun print(ex: T)
}
class MyRuntimeEx : MyException<RuntimeException> {
override fun print(ex: RuntimeException) {
println(ex)
}
}
fun main(args: Array<String>) {
for (exception in ServiceLoader.load(MyException::class.java)) {
exception.print(RuntimeException()) // Compiler error
}
}
The error I am getting is “Out-projected type ‘MyException<*>!’ prohibits the use of ‘public abstract fun print(ex: T)’”
Is there something wrong with the way I have implemented? (I am using version 1.2.0-rc-39)
This is because there is no guarantee that what will be returned will be a MyException<RuntimeException>, it could be a MyException<SomeOtherKindOfException>.
But you can cast it to MyException<RuntimeException>:
ServiceLoader.load(MyException::class.java) as MyException<RuntimeException>
The cast is unchecked, but I believe it will always succeed, since the type is erased.
It is unsafe, of course.
Thanks for the quick reply but this requires me to know that the type is RuntimeException. The point is that I don’t know what (and how many) implementations might be present. As long as they all extend Exception, I should be able to call the print function.
The implementation of the interface is supposed to take care of how to achieve the functionality.
Notice this is not a limitation of Kotlin, but a limitation of the JVM. Due to type erasure, there is no way to guarantee the implementation you receive will behave with the type you’re calling print with.
If you only need to make sure it will behave with any Exception, you might as well give up the type parameter and write the interface as:
public interface MyException {
void print(Exception ex)
}
Thanks @ilya.gorbunov, understood the problem here.
Basically I got that working earlier because Java just throws a warning (which I had ignored). And the places where I was using the above code were having an indirect validation before the code reached that point, so such a scenario was never occurring.