0

I was playing with https://kotlin.github.io/dataframe/overview.html and wanted to see how complicated it looks to call from Java instead of Kotlin. I found many places where there are methods that show in javap output, e.g.:

$ javap -cp . org/jetbrains/kotlinx/dataframe/api/GroupByKt.class
Compiled from "groupBy.kt"
public final class org.jetbrains.kotlinx.dataframe.api.GroupByKt {
...
  public static org.jetbrains.kotlinx.dataframe.api.GroupBy groupBy$default(org.jetbrains.kotlinx.dataframe.DataFrame, boolean, kotlin.jvm.functions.Function2, int, java.lang.Object);
...

where the last method is named groupBy$default. After decompiling the JVM bytecode that Kotlin compiler generated, I see it calling the above function.

However, Eclipse complains that it's undefined and it fails to compile the Java class. Maven complains as well:

[ERROR] /prj/ks/KotlinxDataFrameTest.java:[130,21] cannot find symbol
  symbol:   method groupBy$default(org.jetbrains.kotlinx.dataframe.DataFrame<capture#1 of ?>,boolean,(gb,it)->[...] ""),int,<nulltype>)
  location: class org.jetbrains.kotlinx.dataframe.api.GroupByKt

I thought any method that shows up in javap is callable from Java. What am I missing here?

Edit: added javap -verbose output based on the comment from @broot:

  public static org.jetbrains.kotlinx.dataframe.api.GroupBy groupBy$default(org.jetbrains.kotlinx.dataframe.DataFrame, boolean, kotlin.jvm.functions.Function2, int, java.lang.Object);
    descriptor: (Lorg/jetbrains/kotlinx/dataframe/DataFrame;ZLkotlin/jvm/functions/Function2;ILjava/lang/Object;)Lorg/jetbrains/kotlinx/dataframe/api/GroupBy;
    flags: (0x1009) ACC_PUBLIC, ACC_STATIC, ACC_SYNTHETIC
    Code:
      stack=3, locals=5, args_size=5
         0: iload_3
         1: iconst_1
         2: iand
         3: ifeq          8
         6: iconst_1
         7: istore_1
         8: aload_0
         9: iload_1
        10: aload_2
        11: invokestatic  #32                 // Method groupBy:(Lorg/jetbrains/kotlinx/dataframe/DataFrame;ZLkotlin/jvm/functions/Function2;)Lorg/jetbrains/kotlinx/dataframe/api/GroupBy;
        14: areturn
      StackMapTable: number_of_entries = 1
        frame_type = 8 /* same */
      LineNumberTable:
        line 21: 0
levant pied
  • 3,886
  • 5
  • 37
  • 56
  • 2
    Please add `-verbose` to `javap` and verify if this function isn't synthetic. – broot Jul 05 '23 at 23:25
  • @broot Bingo! Added the output. OK I need to read about synthetic methods. How is Kotlin compiler able to call this method though? Or, alternatively, is that possible to simulate this from Java source? – levant pied Jul 05 '23 at 23:40
  • Synthetic constructs are constructs generated by the compiler that do not appear explicitly or implicitly in the source code (where "implicitly" means stuff like the `values()` and `valueOf(String)` methods of enums, the default constructor, etc.). You can't reference these constructs directly in the source code; Java doesn't allow it (or at least `javac` doesn't allow it). I would guess Kotlin is similar. That doesn't prevent the Kotlin compiler from knowing of the synthetic construct and referencing it "behind the scenes". – Slaw Jul 06 '23 at 00:03
  • That said, I expect you could reference/invoke that synthetic `groupBy$default` method via reflection. – Slaw Jul 06 '23 at 00:05
  • 1
    I think there is one missing information in current answers. We can't call synthetic methods not due to technical inability to do so. Java can call these methods without problems. In fact, they are almost the same as other methods. But they are **intentionally** hidden. They are not "real" methods but byproducts of the compilation process. If we see them, they would add a lot of noise during development. Also, it's not safe to call them as they may change in future versions of the code. In some way they are similar to private methods - only not created be the developer, but the compiler. – broot Jul 06 '23 at 06:33

1 Answers1

1

You should not be able to call a synthetic method from normal Java code. They are (by design) hidden.

A synthetic method is a method that has neither an explicit or implicit declaration. According to JLS 15.12.1, when you call a method you need to give an identifier (the method name) that "appears in the scope of a method declaration with that name" in order to resolve the type that declares it. No such declaration exists by the definition of a synthetic method.

From an intuitive perspective, synthetic methods and fields are only injected into the code while generating the bytecodes. The Java compiler's earlier phases when syntax and semantic analysis occur won't know about the synthetic names ... yet.


As @Slaw notes, you can locate and call a synthetic method using reflection; see What are the interets of synthetic methods? for an example. Likewise, you can probably call them from code injected by a "byte code engineering" library, or similar.

However synthetic methods are an implementation artifact, and (in theory) they could change from one Java version to the next. So writing Java code that relies on calling synthetic methods would a bad idea. Indeed, it is not inconceivable that the Java team would change the Java runtime to make it (more) difficult to do this ... in the same way that they recently made referring to internal JDK classes, etc difficult.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216