Repository navigation
JNI: closureMethodName names the method of closure interfaces - #29
Open
piercifani wants to merge 2 commits into
Open
piercifani wants to merge 2 commits into
piercifani wants to merge 2 commits into
Conversation
Closure interfaces declare one method, `apply`, so Kotlin calls a closure read from Swift as `onTap.apply()`, where Skip and Kotlin's own function types give `onTap()`. Kotlin treats a Java method named `invoke` as the invoke operator, so with `"closureMethodName": "invoke"` the same closure is called as `onTap()`, and Kotlin lambdas still convert to the interface. The name is used for the Java interface, the `@JavaInterface` jextract prints for escaping closures, and the calls into Java, synchronous and async. With a name other than `apply`, closures that a `java.util.function` interface would cover, such as `(Int64) -> Int64` with `LongUnaryOperator.applyAsLong`, get their own interface too, so every closure is called the same way. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stack 25/25 · base:
jni/24-main-actor-async-closure-results· previous: #28Problem
A closure crosses to Java as a functional interface whose one method is
apply. Passing a Kotlin lambda into Swift reads naturally, since Kotlin converts{ … }to the interface. Calling a closure read back from Swift, such as a view model's callback (#21, #28), doesn't:Skip exposes the same properties as Kotlin function types, called as
screen.onTap().Changes
"closureMethodName": "invoke". A new option names the interfaces' method. Kotlin treats a Java method namedinvokeas the invoke operator, so the calls becomescreen.onTap()andscreen.onSelect("BTC"), and Kotlin lambdas still convert to the interface. The default staysapply.@JavaInterfacejextract prints for escaping closures (JNI: escaping closures taking jextracted types; @Sendable/@MainActor closure types #2), and the calls into Java, synchronous and async (JNI: async closures implemented in Java return a CompletableFuture #22).java.util.functioninterfaces with a custom name. Closures such as(Int64) -> Int64, which map toLongUnaryOperatorand itsapplyAsLong, get their own interface instead, so every closure is called the same way.Kotlin in this PR
The sample sets
"closureMethodName": "invoke", and its tests now call closures as functions.ScreenCallbacksTest.kt:ClosuresTest.ktcalls a returned closure asformat(Item.init(it, 1)), and still passes{ it * 2 }to(Int) -> Int, which now has its own interface.Why Skip needs it
Kotlin code written against Skip calls these callbacks as functions. With
invoke, the same Kotlin code compiles against jextract's output.Testing
./gradlew :Samples:SwiftJavaExtractJNIKotlinSampleApp:testpasses (56 tests). That covers escaping, non-escaping, async and returned closures, and primitive ones that used to beLongUnaryOperator.JNIClosureMethodNameTests(2 tests): the Java interfaces and the Swift wrapper useinvoke, and nojava.util.functioninterface is used.swift testpasses; config docs regenerated.🤖 Generated with Claude Code