Repository navigation
jextract: closureMethodName names the method of closure interfaces - #953
Open
piercifani wants to merge 1 commit into
Open
piercifani wants to merge 1 commit into
piercifani wants to merge 1 commit into
Conversation
Closure interfaces declare one method, `apply`, so Kotlin code calls a closure value as `handler.apply(x)`. Kotlin treats a Java method named `invoke` as the invoke operator, so with `"closureMethodName": "invoke"` the same closure is called as `handler(x)`, and Kotlin lambdas still convert to the interface. The default stays `apply`. The name is used for the Java interface, the `@JavaInterface` printed for escaping closures and the call into Java, and the method looked up for non-escaping closures. 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>
Contributor
|
I think that's a good point. |
Collaborator
|
I wouldn't mind switching to calling it invoke by default if it happens to help kotlin interop. For specific interfaces we need we'd generate the specific names still. Could you look into that? |
Collaborator
|
alternatively we could generate a |
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.
Problem
A Swift closure crosses to Java as a functional interface with one method,
apply. From Kotlin, passing a lambda into Swift reads naturally, since Kotlin converts{ … }to the interface. Calling a closure value doesn't:Kotlin function types are called as
handler("hi"), and that's what Kotlin code expects.Changes
"closureMethodName", a new option inswift-java.config(JNI mode), names the interfaces' method. The default staysapply.Kotlin treats a Java method named
invokeas the invoke operator, so with"closureMethodName": "invoke":handler("hi");handler.invoke("hi").The name is used in four places:
@JavaInterfaceprinted for escaping closures;With a name other than
apply, closures that ajava.util.functioninterface would cover, such as(Int64) -> Int64withLongUnaryOperator.applyAsLong, get their own interface too, so every closure is called the same way.Testing
JNIClosureMethodNameTests(3 tests):invoke;java.util.functioninterface is used with a custom name;applyandLongUnaryOperatorremain the default.JExtractSwiftPluginand"closureMethodName": "invoke", called from Java. An escaping(String) -> Voidstored and called back from Swift, and a non-escaping(Int64) -> Int64, both reach the Java lambdas throughinvoke.swift testpasses; config docs regenerated.🤖 Generated with Claude Code