Call Kotlin inline function from Java - kotlin

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();

Related

JUnit 5 and Arguments.of() with functions

Writing a JUnit 5 parameterized test and need to pass functions to the test using Arguments.of(), but there are 2 compile errors that I don't know how to fix. Any help would be appreciated.
The method of(Object...) in the type Arguments is not applicable for the arguments (boolean, String::length)
The target type of this expression must be a functional interface
public static Stream<Arguments> some() {
return Stream.of(Arguments.of(true, String::length));
}
#ParameterizedTest
#MethodSource
public <T> void some(final T input, final Function<String, Integer> length) {
}
The following works as expected.
public void sample() {
some(true, String::length);
}
Wrap the arguments in a helper method
Similar to the answer "wrap it in a class", but possibly less intrusive, is to use a helper method to pass the functional interface as a java.lang.Object.
For example, the first raw method reference, Math::ciel, in this parameterized test:
#ParameterizedTest
#MethodSource("testCases")
void shouldExerciseMethod(Function<Double, Double> method, Double expected) {
assertEquals(expected, method.apply(1.5d), 1.0E-8d);
}
static Stream<Arguments> testCases() {
return Stream.of(Arguments.of(Math::ceil, 2.0d),
Arguments.of(Math::floor, 1.0d));
}
causes this compilation error:
java: method of in interface org.junit.jupiter.params.provider.Arguments cannot be applied to given types;
required: java.lang.Object[]
found: Math::ceil,double
reason: varargs mismatch; java.lang.Object is not a functional interface
which you can get around by passing the arguments through a helper method:
static <T, U> Arguments args(Function<T, U> method, U expected) {
return Arguments.of(method, expected);
}
so:
static Stream<Arguments> testCases() {
return Stream.of(args(Math::ceil, 2.0d),
args(Math::floor, 1.0d));
}
My attempts to make the idiom more general using varargs failed with variations on the same error, so I have ended up overloading it whenever I need another signature.
The function needs to be wrapped in a class.
public static class P {
private final Function<String, Integer> mFunction;
public P(final Function<String, Integer> function) {
mFunction = function;
}
public Function<String, Integer> function() {
return mFunction;
}
}
public static Stream<Arguments> some() {
return Stream.of(Arguments.of(3, "abc", new P(String::length)));
}
#ParameterizedTest
#MethodSource
public <T> void some(final int expect, final String input, final P p) {
assertEquals(expect, p.function().apply(input));
}
I liked #adrian-redgers solution, but I think overloading a method for each signature needed is a bit overkill.
You only really need to convert the functional interface to an object. So the solution I implemented was:
/**
* Helps to use {#link org.junit.jupiter.params.provider.Arguments#of(Object...)}, as functional
* interfaces cannot be converted into an object directly.
*/
public class ArgumentsWrapper {
private ArgumentsWrapper() {
throw new IllegalStateException(
ArgumentsWrapper.class + " util class cannot be instantiated");
}
public static <T, U> Function<T, U> wrap(Function<T, U> function) {
return function;
}
}
Then, it can be used as:
public static Stream<Arguments> testMapAlarmTypeConfigWithLanguage() {
return Stream.of(
// Statically imported ArgumentsWrapper#wrap
Arguments.of(null, wrap(AlarmTypeConfig::getNameInEnglish)),
Arguments.of("en-us", wrap(AlarmTypeConfig::getNameInEnglish)),
Arguments.of("es-es", wrap(AlarmTypeConfig::getNameInSpanish)));
}

Java8 Higher-Order Functions and Kotlin Lambdas interoperability

I have a Java example where a method is implemented as
#Override
public Function<ISeq<Item>, Double> fitness() {
return items -> {
final Item sum = items.stream().collect(Item.toSum());
return sum._size <= _knapsackSize ? sum._value : 0;
};
}
IntelliJ's automatic translation of it to Kotlin is
override fun fitness(): Function<ISeq<Item>, Double> {
return { items:ISeq<Item> ->
val sum = items.stream().collect(Item.toSum())
if (sum.size <= _knapsackSize) sum.value else 0.0
}
}
(I made the type of items explicit and changed return to 0.0)
Still I see that there are compatibility problems with Java's Function and Kotlin native lambdas, but I'm not that the most familiar with these. Error is:
Question is: is it possible to override in Kotlin the external Java library's fitness() method on this example and if so how ?
Problem:
You are returning a (Kotlin) lambda ISeq<Knapsack.Item> -> Double. But this is not what you want. You want to return a Java Function<ISeq<Knapsack.Item>, Double>.
Solution:
You can use a SAM Conversion to create a Function.
Just like Java 8, Kotlin supports SAM conversions. This means that
Kotlin function literals can be automatically converted into
implementations of Java interfaces with a single non-default method,
as long as the parameter types of the interface method match the
parameter types of the Kotlin function.
I created a minimal example to demonstrate that. Consider you have a Java class like this:
public class Foo {
public Function<String, Integer> getFunction() {
return item -> Integer.valueOf(item);
}
}
If you want to override getFunction in Kotlin you would do it like this:
class Bar: Foo() {
override fun getFunction(): Function<String, Int> {
return Function {
it.toInt()
}
}
}
When returning lambda as Java's functional interface, you have to use explicit SAM constructor:
override fun fitness(): Function<ISeq<Item>, Double> {
return Function { items:ISeq<Item> ->
val sum = items.stream().collect(Item.toSum())
if (sum.size <= _knapsackSize) sum.value else 0.0
}
}
Also don't forget to import java.util.function.Function since Kotlin has its own class of that name

Extension functions issue

Run into some difficulties while using extension functions with existing java api. Here some pseudocode
public class Test {
public Test call() {
return this;
}
public Test call(Object param) {
return this;
}
public void configure1() {
}
public void configure2(boolean value) {
}
}
Kotlin test
fun Test.call(toApply: Test.() -> Unit): Test {
return call()
.apply(toApply)
}
fun Test.call(param: Any, toApply: Test.() -> Unit): Test {
return call(param)
.apply(toApply)
}
fun main(args: Array<String>) {
val test = Test()
//refers to java method; Unresolved reference: configure1;Unresolved reference: configure2
test.call {
configure1()
configure2(true)
}
//refers to my extension function and works fine
test.call(test) {
configure1()
configure2(true)
}
}
Why only function with param works fine ? what’s the difference ?
Kotlin will always give precedence to the classes member functions. Since Test:call(Object) is a possible match, Kotlin selects that method rather than your extension function.
The extension function with the added parameter is resolved the way you expect because the Test class does not have any member functions that would take precedent (no matching signature), so your extension method is selected.
Here is a link to the Kotlin documentation as to how extension functions are resolved: https://kotlinlang.org/docs/reference/extensions.html#extensions-are-resolved-statically

Kotlin: Is local function passed to inlined functions as parameter inlined?

When passing a lambda or anonymous function to inlined functions as a parameter, it's quite simple, the code is pasted to the calling position, but when passing a local function as a parameter, the result seems different(shown as below). I wonder if it's inlined? Why or why not?
For example:
inline fun foo(arg: () -> Int): Int {
return arg()
}
fun bar(): Int {
return 0
}
fun main(args: Array<String>) {
foo(::bar)
}
And decompiled Java code:
public final class InlinedFuncKt {
public static final int foo(#NotNull Function0 arg) {
Intrinsics.checkParameterIsNotNull(arg, "arg");
return ((Number)arg.invoke()).intValue();
}
public static final int bar() {
return 0;
}
public static final void main(#NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
bar();
}
}
bar() is not declared to be inlined. So why would you expect it to be inlined?!
In other words: it would be simply wrong that the signature of method A affects (implicitly) the signature of another method B.
Your idea would (somehow) affect "semantics" of bar() - just because you used bar() as argument to another method call.
As you can in the decompiled code, kotlin does not inline bar in your case, but it does inline it if it is declared as inline fun bar().
The rule is that lambdas are inlined when they are passed to an inlined function. In all other cases like passing a function reference or a lambda object, no inlining is done.

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.