Throwing runnables and backward compat

I have a collection of utilities that I use both from my existing Java code and new Kotlin code. Among those are often utilities that take lambdas.

inline fun <T> foo(crossinline lambda : () -> T) : T {
  [...]
  return lambda()
}

When calling from Kotlin this is perfectly fine, because Kotlin does not have checked exceptions.

When calling from java, crossinline lambda becomes a Function0<?>. Note the absence of throw clauses.

So from Java, I can’t call

  foo(() -> { if (worldNeedsSaving) { saveTheWorld(); } else throw new CheckedException(); });

…because Java will complain that CheckedException is not handled.

The only way I have found so far to make this work is to use Java functional classes.

@FunctionalInterface public interface ThrowingSupplier<T> {
  T get() throws Exception;
}

inline fun <T> foo(lambda : ThrowingSupplier<T>) {
  ...
}

But this means the lambda can no longer crossinline, which has other drawbacks.

Intuitively I would say that either Kotlin, as a language without checked exceptions, should compile () -> T into Function0<T> throws Exception, or that I should be able to annotate my argument with @Throws.

Is there a better solution than mine above, in particular one that would let me keep crossinline ?

2 Likes