# An Empirical Study of Kotlin-Java Interactions

Qiong Feng, Huan Ji, Xiaotian Ma  Nanjing University of Science and
TechnologyNanjingChina qiongfeng, alex<EMAIL_ADDRESS>and  Peng Liang
Wuhan UniversityWuhanChina<EMAIL_ADDRESS>
(2024)

###### Abstract.

Background: Since Google introduced Kotlin as an official programming language
for developing Android apps in 2017, Kotlin has gained widespread adoption in
Android development. The interoperability of Java and Kotlin’s design nature
allows them to coexist and interact with each other smoothly within a project.
Aims: However, there is limited research on how Java and Kotlin interact with
each other in real-world projects and what challenges are faced during these
interactions. The answers to these questions are key to understanding these
kinds of cross-language software systems. Methods: In this paper, we
implemented a tool named DependExtractor, which can extract 11 kinds of
Kotlin-Java dependencies, and conducted an empirical study of 23 Kotlin-Java
real-world projects with 3,227 Java and 8,630 Kotlin source files. Results:
Our findings revealed that Java and Kotlin frequently interact with each other
in these cross-language projects, with access and call dependency types being
the most dominant. Compared to files interacting with other files in the same
language, Java/Kotlin source files, which participate in the cross-language
interactions, undergo more commits. Additionally, among all Kotlin-Java
problematic interactions, we identified seven common mistakes, along with
their fixing strategies. Conclusions: The findings of this study can help
developers understand and address the challenges in Kotlin-Java projects.

Kotlin, Java, Code Dependency, Cross Language

††copyright: acmlicensed††journalyear: 2024††doi: XXXXXXX.XXXXXXX††conference:
Make sure to enter the correct conference title from your rights confirmation
email; June 03–05, 2018; Woodstock, NY††isbn: 978-1-4503-XXXX-X/18/06

##  1\. Introduction

Since Google introduced Kotlin as an official programming language for
developing Android apps in 2017, Kotlin has gained widespread adoption in
Android development. According to recent studies, a significant of Android
apps have been continuously migrated from Java to Kotlin (Ardito et al., 2020;
Mateus and Martinez, 2020). The interoperability of Java and Kotlin’s design
nature allows them to coexist and evolve smoothly in a single project.
Meanwhile, understanding the dependencies among software entities is
fundamental to various aspects of software analysis, such as architecture
recovery, code smell detection, and software quality evaluation (Mo et al.,
2019; Cui et al., 2019; Xiao et al., 2022). Extracting and understanding the
dependency interactions between Java and Kotlin code is essential for
conducting software analysis in such cross-language software systems. Despite
the increasing popularity of Kotlin and its interoperability with Java, there
is limited research on how Java and Kotlin interact with and depend on each
other in real-world projects. Furthermore, recent studies (Li et al., 2023b)
have shown that a large percentage of bug fixes in deep learning frameworks
implemented in Python and C++ involve modifying source code in both
programming languages. Moreover, the complexity of code changes for such bug
fixes is significantly higher than that of fixes in single-programming-
language scenarios (Li et al., 2023a). Similarly, many Android applications
are developed using both Java and Kotlin, mirroring the dual-language nature
of deep learning frameworks which commonly employ Python and C++. Unlike the
interactions between Python and C++, which rely on their compiled public APIs,
Java and Kotlin, both being based on the Java Virtual Machine (JVM), can
extensively depend on each other at the source code level. This raises the
question of whether Kotlin-Java software systems also incur higher maintenance
costs and are prone to cross-language bugs, similar to other multi-language
systems like Python-C++. In other words, what challenges do developers face in
the implementation and maintenance of Kotlin-Java systems? Understanding these
challenges can assist researchers and practitioners in designing solutions and
tools to navigate these issues and ensure the development of high-quality
Kotlin-Java software systems.

Although Google Android have provided documentation to guide developers on
integrating Kotlin and Java (and, [n. d.]), the challenges faced in real-world
projects remain largely unknown. In this paper, we propose to investigate into
the dependency relations between Kotlin and Java in real-world projects to
better understand the challenges associated with their interactions. To this
end, we conducted an empirical study of 23 open-source projects, comprising
3,227 Java and 8,630 Kotlin source files. We developed a static code analysis
tool to extract 11 kinds of dependency relations between Kotlin and Java code
entities within these projects. Our findings indicate that Java and Kotlin
frequently interact in these cross-language projects, with access and call
dependency types being the most prevalent.

Compared to files interacting solely within the same language, Java/Kotlin
source files that act as the interface for cross-language interactions have
undergone more commits, but not necessarily contain a higher volume of lines
of code (LOC). Furthermore, we identified seven common mistakes in Kotlin-Java
problematic interactions, which deserve special attention from developers. To
the best of our knowledge, this work is the first to explore Kotlin-Java
dependency relations and to expose common problems in these interactions
within real-world projects. The dependency analysis tool that we have
implemented and the recurring patterns in Kotlin-Java problematic interactions
can assist developers in comprehending and uncovering potential pitfalls in
such cross-language systems.

To summarize, our contributions in this paper are as follows:

  * •

We implemented a static code analysis tool named DependExtractor to extract
dependencies between Java and Kotlin, addressing a gap that existing static
code analysis tools cannot resolve regarding such dependencies.

  * •

We demonstrated that the source files involved in Kotlin-Java interactions
require undergoing more commits and changes than those only involved in a
single language. It proves that the Kotlin-Java interface is not stable and
actively changing.

  * •

We identified seven common mistakes which cause bugs and maintenance effort in
Kotlin-Java problematic interactions. These common mistakes can serve as a
taxonomy and deserve developers’ special attention.

##  2\. Approach

In this section, we describe our approach to extract Kotlin-Java dependencies
and to identify recurring patterns in Kotlin-Java problematic interactions
which incur maintenance cost.

###  2.1. Kotlin-Java Dependency Extraction

We implemented a tool called DependExtractor to extract dependencies between
Kotlin and Java code entities. DependExtractor first utilized the Kotlin
compiler to resolve Kotlin and Java source files into PSI (Program Structure
Interface, similar to Abstract Syntax Tree) elements, including their types,
reference types, and locations. Subsequently, it extracted dependency
relations between pairs of PSI elements. Finally, these dependencies into a
graph containing all PSI elements are aggregated and can be exported in JSON
format, with each node representing a Kotlin or Java source file and each edge
representing the dependencies between two source files. Following the
definitions of dependency relations from related works (Jin et al., 2019; dep,
[n. d.]; und, [n. d.]), DependExtractor is capable of extracting 9 types of
Java-Java dependencies, 14 types of Kotlin-Kotlin dependencies, and 11 types
of Kotlin-Java dependencies. As this paper focuses mainly on Kotlin-Java
interactions, we list the 11 types of Kotlin-Java dependencies and their
descriptions in Table 1.

Table 1. Kotlin-Java Dependency Types Extracted by DependExtractor DepType |  Description
---|---
Access |  an expression accesses a field or property (kotlin side)
Call |  an expression calls a method
Create |  an expression creates an object
Extend |  a class extends a parent class
Extension |  a Kotlin method or property extension
Local Variable Typed (LVT) |  a local variable uses a class as its type
Property Typed (PT) |  a Kotlin property uses a Java class as its type
Implement |  a class implements an interface
Import |  a statement imports a type
Parameter |  a method uses a class as its parameter
Return |  a method returns a class type

As observed from Table 1, Access signifies that an expression in one source
file accesses a field or property of a class in another source file, while
Call indicates that an expression in one source file calls a method of a class
in another source file. Note that we not only record the dependency type
between two source files, but also resolve dependency relations at a fine-
grained granularity, capturing details such as the expression statement,
locations, and type information for each specific dependency. This fine-
grained approach can be valuable for future refactoring research, including
but not limited to null safety addressing, exception handling, etc.

Table 2. Demographic Information of Kotlin-Java Projects in Our Study ProjectName | #Stars | Kotlin(%) | Java(%) | Domain | Repository Link
---|---|---|---|---|---
bilimiao2 | 1300 | 73.5 | 24.7 | Android | https://github.com/10miaomiao/bilimiao2
DataStats | 32 | 81.8 | 17.9 | Android | https://github.com/takke/DataStats
dgs-framework | 3000 | 82.2 | 16 | Library | https://github.com/Netflix/dgs-framework
FDPClient | 353 | 65.4 | 34 | Minecraft | https://github.com/SkidderMC/FDPClient
Flap | 286 | 52.4 | 47.6 | Android | https://github.com/AlanCheen/Flap
grpc-kotlin | 1100 | 84.3 | 7.1 | Library | https://github.com/grpc/grpc-kotlin
husi | 192 | 74.2 | 14.2 | Android | https://github.com/xchacha20-poly1305/husi
intellij-powershell | 67 | 73.1 | 6.4 | IDEA Plugin | https://github.com/ant-druha/intellij-powershell
java-stellar-anchor-sdk | 34 | 62.2 | 37.7 | Server backend | https://github.com/stellar/java-stellar-anchor-sdk
javalin | 7200 | 89 | 10.6 | Library | https://github.com/javalin/javalin
jetbrains | 36 | 74.8 | 24.4 | IDEA Plugin | https://github.com/sourcegraph/jetbrains
karibu-testing | 104 | 78.6 | 6 | Library | https://github.com/mvysny/karibu-testing
legado | 23848 | 77.6 | 14.3 | Android | https://github.com/gedoor/legado
LiquidBounce | 1227 | 81.5 | 9.9 | Minecraft | https://github.com/CCBlueX/LiquidBounce
MyExpenses | 712 | 64.8 | 34.5 | Android | https://github.com/mtotschnig/MyExpenses
NightX-Client | 103 | 61.3 | 38.4 | Minecraft | https://github.com/Aspw-w/NightX-Client
RootEncoder | 738 | 55.8 | 42.1 | Android | https://github.com/pedroSG94/RootEncoder
SeriesGuide | 1910 | 68.4 | 31.6 | Android | https://github.com/UweTrottmann/SeriesGuide
simbrain | 87 | 60.7 | 38 | Desktop App | https://github.com/simbrain/simbrain
SkyHanni | 172 | 84.2 | 15.7 | Minecraft | https://github.com/hannibal002/SkyHanni
SkytilsMod | 956 | 90.1 | 9.7 | Minecraft | https://github.com/Skytils/SkytilsMod
tasks | 3275 | 92.4 | 7.5 | Android | https://github.com/tasks/tasks
wire | 4172 | 62.1 | 29.4 | Library | https://github.com/square/wire

###  2.2. Common Mistake Identification in Kotlin-Java Interaction

To detect recurring patterns associated with Kotlin-Java problematic
interactions, we initially mined code repositories to narrow the problematic
commit scope for manual inspection. Subsequently, we conducted a thorough
manual inspection of code changes to identify and classify code patterns
related to Kotlin-Java problematic interactions.

####  2.2.1. Locate Commits to Address Kotlin-Java Problems

We conducted the following filtering process to narrow the scope of potential
commits to address Kotlin-Java issues.

  * f1)

A commit’s comment must contain the words ‘fix,’ ‘bug,’ ‘issue,’ or
‘exception’, and the modified files in a commit must contain file paths with
extensions either .java or .kt. All commits that satisfy condition f1 will be
added to a collection C1 and proceed to the next filter.

  * f2)

The modified Java or Kotlin source files in a commit must be involved in
Kotlin-Java interactions. For each project, we can obtain the dependency graph
of its latest release using the approach outlined in Section 2.1 and identify
the files in Kotlin-Java dependency edges. If a commit contains modified files
on Kotlin-Java dependency edges, we add it to collection C2 and proceed to the
process of manual inspection.

####  2.2.2. Identify Common Mistakes of Kotlin-Java Problems through Manual
Inspection

We establish a protocol for this manual inspection process. First, we located
the code changes in Kotlin or Java source file. Then we checked whether the
code changes are related with Kotlin-Java interactions. We did this by tracing
the code changes down to its reference type. For instance, if a line of code
in a Kotlin file is deleted, we get the variables and methods in this line and
track the variables down to check whether it is a type of Java class, method,
etc. Subsequently, we check whether any new code snippets are added in the
Kotlin file near the location of the deleted code line. If present, we
compared the differences between the added line and the deleted line. Last, we
check the commit comments and discussed what problems developers are trying to
address and why developers made such changes.

This step required the dedicated efforts of 2 students with 4 years of Java
and 3 years of Kotlin development experience, and one senior researcher with
14 years of Java and 3 years of Kotlin development experience. We followed the
practice described in (Campbell et al., 2013), allowing the senior researcher
to establish the procedure for identifying code changes and training the
students with examples. Then, the two students collaborated to identify code
changes and categorize the changes’ reasons. If disagreements occurred, the
senior researcher would review the specific cases and discuss them with the
two students until a consensus was reached.

##  3\. Study Design

###  3.1. Subjects

The objective of our study is to investigate the interactions between Kotlin
and Java code within real-world projects, and we need to mine open source
projects with both Kotlin and Java code. To achieve this, we first applied
GitHub API to search repositories with Kotlin code through the GitHub
link111https://github.com/search?q=language%3AKotlin+&type=repositories. We
further filtered those Kotlin repositories according to the following
criteria:

  * 1)

The repository must contain Java code alongside Kotlin, with Java code
constituting more than 3% of the total code;

  * 2)

The repository should have a star count of no less than 20;

  * 3)

The repository must have been updated within the last 48 hours relative to our
data collection time, which is 12:00 PM on Jan 15, 2024.

Since GitHub does not support searching repositories by multiple languages, we
clicked and manually inspected each repository to assess the ratio of
programming languages and to fulfill Criterion 1). We established a minimum
threshold of 3% for Java code to ensure its active participation in the
projects’ functionalities. Criteria 2) and 3) focus on selecting repositories
that are actively maintained, which are essential for identifying relevant
challenges. By applying these criteria, we identified 23 projects, and their
demographic information is presented in Table 2.

These 23 projects span various domains, with 9 focused on Android app
development, 5 on Minecraft games, 2 on IntelliJ IDEA Plugins, and 7
encompassing other areas. The percentage of Java code ranges from 6% in the
karibu-testing project to 47.6% in the Flap project. In contrast, the
percentage of Kotlin code varies from 52.4% in the Flap project to 92.4% in
the tasks project. The wide and diverse range of Java and Kotlin code present
in these projects enables us to gain a deeper understanding of Kotlin-Java
interactions.

###  3.2. Research Questions

We investigated the following Research Questions (RQs) to gain insight into
Kotlin-Java interactions and challenges associated with their interactions.

RQ1. How do dependencies among code entities look like in Kotlin-Java
projects? Kotlin is designed to be fully interoperable with Java, allowing
code entities to be seamlessly accessed across both languages. Ideally,
dependencies between Kotlin and Java should exhibit the same characteristics
as those within homogeneous Kotlin or Java codebases. The answer to this
question can enhance our understanding of such cross-language software systems
and form the basis for further software analysis in Kotlin-Java projects.

RQ2. Is the maintenance cost in files involved in Kotlin-Java interactions
significantly higher than in files without Kotlin-Java interactions? Recent
studies on multi-language systems, such as those involving Python and C++,
have shown that to address bugs occurring in the interface of two languages,
developers need to modify code in both languages, resulting in a higher number
of lines of code (LOCs) (Li et al., 2023a). This observation raises the
question of whether Kotlin-Java software systems are also prone to such cross-
language maintenance costs. The answer to this question could pinpoint
maintenance hotspots within these Kotlin-Java systems.

RQ3. Are there common mistakes in Kotlin-Java interactions? Previous research
proposed various techniques for detecting code smells or anti-patterns within
a single-language codebase. More recent studies have found that bugs and
security problems in multiple language systems (Li et al., 2023b). For
instance, a recent study has uncovered security issues arising from
interactions between Java and C++ code (Li et al., 2022). By investigating
whether there exist common mistakes in Kotlin-Java interactions, we aim to
evaluate the problems associated with Kotlin-Java interactions and pinpoint
the scenarios that may require closer attention when handling such
interactions.

##  4\. Results

###  4.1. Dependencies in Kotlin-Java Projects

Using the approach detailed in Section 2.1, we developed a tool capable of
extracting dependencies within Kotlin-Java projects. We utilized this tool on
the most recent versions of our 23 selected projects, and the results are
presented in Table 3. This table includes columns labeled #J and #K, which
denote the counts of Java and Kotlin source files, respectively. The J-J and
K-K columns represent the number of dependencies between pairs of Java source
files and pairs of Kotlin source files, respectively. Additionally, the K-J
column indicates the number of dependencies from a Kotlin source file to a
Java source file. It is interesting that in these 23 projects we did not
observe any Java-Kotlin dependencies (DependExtractor was tested thoroughly).
This may be due to our subject selection criteria, and the primary language of
these projects is Kotlin, in which developers tend to use Kotlin to depend on
Java for functionalities. All dependencies in this table are counted without
weights. The last column shows the ratio of Kotlin-Java dependencies to the
minimum of Java-Java and Kotlin-Kotlin dependencies. Since source files with
fewer numbers can determine dependency intensity, we compare Kotlin-Java
dependencies with the minimum dependencies in a single language to check the
prevalence of their interactions.

Table 3. Dependency Statistics in Kotlin-Java Projects ProjName | #J | #K | J-J | K-K | K-J | $\frac{K-J}{Min(J-J,K-K)}$%
---|---|---|---|---|---|---
bilimiao2 | 88 | 489 | 222 | 5979 | 122 | 55.0
DataStats | 9 | 10 | 2 | 24 | 46 | 2300.0
dgs-fw | 108 | 305 | 93 | 1648 | 567 | 609.7
FDPClient | 242 | 621 | 320 | 8886 | 1291 | 403.4
Flap | 20 | 104 | 19 | 636 | 19 | 100.0
grpc-k | 8 | 83 | 2 | 285 | 8 | 400.0
husi | 29 | 175 | 81 | 1913 | 494 | 609.9
intellij-p | 7 | 162 | 6 | 929 | 11 | 183.3
java..-sdk | 548 | 260 | 1381 | 810 | 4796 | 592.1
javalin | 57 | 260 | 46 | 2600 | 635 | 1380.4
jetbrains | 95 | 300 | 94 | 2104 | 204 | 217.0
karibu-t | 7 | 112 | 6 | 171 | 3 | 50.0
legado | 87 | 746 | 269 | 12057 | 89 | 33.1
LiquidBounce | 84 | 575 | 11 | 9114 | 11 | 100.0
MyExpenses | 325 | 703 | 678 | 9756 | 2842 | 419.2
NightX-Client | 184 | 253 | 286 | 3223 | 1244 | 435.0
RootEncoder | 136 | 334 | 340 | 3209 | 395 | 116.2
SeriesGuide | 176 | 391 | 216 | 4483 | 1468 | 679.6
simbrain | 325 | 481 | 756 | 8140 | 1434 | 189.7
SkyHanni | 302 | 697 | 301 | 14271 | 1898 | 630.6
SkytilsMod | 89 | 302 | 8 | 3639 | 107 | 1337.5
tasks | 83 | 639 | 63 | 9028 | 1245 | 1976.2
wire | 218 | 628 | 168 | 9935 | 60 | 35.7
Average |  |  |  |  |  | 528.6

As shown in Table 3, Kotlin and Java source files frequently interact. For
instance, in the bilimiao2 project, there are 122 Kotlin-Java dependencies
within 88 Java and 489 Kotlin files. If we divide 122 Kotlin-Java dependencies
by the minimum of Java-Java and Kotlin-Kotlin dependencies, we obtain 55.0%.
This significant ratio indicates that Kotlin-Java dependencies are prevalent
in this project. Similar results are observed in other projects. In the
DataStats project, for example, there are 46 Kotlin-Java dependencies within 9
Java and 10 Kotlin files, outnumbering 2 Java-Java and 24 Kotlin-Kotlin
dependencies. The resulting ratio of 2300.0% underscores the dominance of
Kotlin-Java dependencies in this project. Overall, the last column of this
table reveals that the ratio of Kotlin-Java dependencies ranges from 33.1% in
the legado project to 2300.0% in the DataStats project, with an average of
528.6%. This average indicates that, on average, Kotlin-Java interactions are
five times more prevalent than the minority of single-language interactions.

Table 4. Dependency Types in Kotlin-Java Interactions ProjName | Access | Call | Create | Extend | Extension | LVT | PT | Implement | Import | Parameter | Return
---|---|---|---|---|---|---|---|---|---|---|---
bilimiao2 | 8 | 43 | 3 | 1 | 1 | 25 | 41 | 3 | 39 | 15 | 9
DataStats | 163 | 89 | 0 | 0 | 0 | 29 | 13 | 0 | 9 | 0 | 0
dgs-framework | 153 | 112 | 953 | 8 | 0 | 66 | 14 | 4 | 187 | 50 | 6
FDPClient | 5919 | 729 | 31 | 54 | 0 | 846 | 99 | 0 | 276 | 12 | 16
Flap | 14 | 3 | 3 | 0 | 0 | 7 | 4 | 0 | 3 | 0 | 1
grpc-kotlin | 89 | 3 | 1 | 0 | 0 | 0 | 6 | 0 | 0 | 1 | 0
husi | 1523 | 81 | 120 | 14 | 64 | 167 | 4 | 0 | 111 | 40 | 64
intellij-powershell | 8 | 3 | 1 | 0 | 0 | 1 | 0 | 0 | 3 | 0 | 1
java-stellar-anchor-sdk | 5382 | 5115 | 2126 | 20 | 1 | 3462 | 882 | 3 | 1843 | 100 | 2752
javalin | 204 | 1315 | 29 | 0 | 2 | 157 | 69 | 4 | 307 | 90 | 745
jetbrains | 90 | 68 | 26 | 4 | 0 | 55 | 35 | 1 | 69 | 15 | 25
karibu-testing | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0
legado | 5 | 51 | 32 | 0 | 0 | 21 | 14 | 4 | 24 | 18 | 8
LiquidBounce | 8 | 9 | 0 | 0 | 0 | 0 | 13 | 0 | 3 | 0 | 0
MyExpenses | 3623 | 1365 | 124 | 63 | 5 | 1420 | 1086 | 40 | 2646 | 243 | 737
NightX-Client | 4002 | 1277 | 141 | 40 | 0 | 443 | 141 | 0 | 333 | 3 | 23
RootEncoder | 243 | 399 | 65 | 6 | 0 | 46 | 33 | 9 | 134 | 47 | 6
SeriesGuide | 1142 | 581 | 700 | 94 | 4 | 488 | 346 | 23 | 506 | 147 | 43
simbrain | 522 | 711 | 321 | 36 | 14 | 402 | 286 | 14 | 411 | 110 | 124
SkyHanni | 2042 | 24 | 16 | 98 | 21 | 519 | 887 | 1 | 280 | 71 | 294
SkytilsMod | 83 | 20 | 0 | 0 | 0 | 19 | 7 | 0 | 49 | 1 | 1
tasks | 378 | 874 | 520 | 4 | 1 | 398 | 354 | 8 | 460 | 87 | 77
wire | 45 | 76 | 18 | 4 | 0 | 50 | 7 | 0 | 24 | 0 | 4
Total | 25647 | 12948 | 5231 | 446 | 113 | 8621 | 4341 | 114 | 7717 | 1051 | 4936

Figure LABEL:fig:deps depicts the circular layout of dependencies in three
projects. The nodes on the circle’s edge represent source files. The blue,
red, and purple curved lines connecting two nodes represent Kotlin-Kotlin,
Java-Java, and Kotlin-Java dependencies, respectively. It is evident that
Kotlin-Java dependencies are not confined to a specific area; instead, they
are spread across the entire systems, proving Kotlin-Java interoperability in
real-world software projects.

Table 4 presents the statistics of Kotlin-Java dependency types in each
project. As observed in this table, certain dependency types are present in
some projects but not in others. For instance, the “Extension” dependency type
is found in 9 projects, while the remaining 14 projects do not exhibit this
type. We suspect this discrepancy is due to the distinct characteristics of
the projects. However, all 11 defined types of Kotlin-Java dependencies can be
observed across all projects. The top two most frequent dependency types among
Kotlin-Java interactions are “Access” and “Call”.

To answer RQ1, the dependency extraction from 23 open-source Kotlin-Java
projects spanning various domains reveals that Kotlin-Java dependencies and
interactions are widespread. Kotlin-Java dependencies can occur more
frequently than minor single-language interactions, with “Access” and “Call”
being the top two most frequent dependency types. Furthermore, Kotlin-Java
dependencies are distributed across the entire system rather than confined to
a local area, thus validating the interoperability between Kotlin and Java.

Table 5. Maintenance Cost of Kotlin/Java Source Files in Kotlin-Kotlin, Java-Java, and Kotlin-Java ProjectName | Kotlin Files in Kotlin-Kotlin | Java Files in Java-Java | Kotlin Files in Kotlin-Java
---|---|---|---
#Avg_Cmt_K | Avg_LOC_K | #Avg_Cmt_J | Avg_LOC_J | #Avg_Cmt_Kj | Avg_LOC_Kj
bilimiao2 | 17 | 116.5 | 1.5 | 5.7 | 2.8 | 49.7
DataStats | 4.6 | 22.0 | 4.5 | 47.0 | 20.5(4.5x) | 27.2
dgs-framework | 10.8 | 97.0 | 3.3 | 22.0 | 6.3 | 81.1
FDPClient | 11.1 | 60.6 | 14.8 | 110.1 | 37.5(3.4x) | 53.9
Flap | 13.3 | 102.1 | 12 | 58.6 | 27.9(2.1x) | 61.8
grpc-kotlin | 6.5 | 30.0 | 5 | 14 | 11(1.7x) | 32.3
husi | 3.9 | 24.0 | 3.5 | 34.8 | 23.7(6.1x) | 20.8
intellij-powershell | 11.5 | 53.7 | 11.3 | 90.3 | 38.3(3.3x) | 26.3
java-stellar-anchor-sdk | 7.3 | 113.9 | 7.3 | 52.9 | 14.9(2.0x) | 102.3
javalin | 13.9 | 78.3 | 5.6 | 23.4 | 8.6 | 62.5
jetbrains | 13.2 | 78.2 | 10.3 | 76.9 | 36.7(2.8x) | 44.6
karibu-testing | 10.5 | 99.5 | 8.4 | 62.6 | 3.4 | 121.7
legado | 41.9 | 825.3 | 2.8 | 8.5 | 3.7 | 170.3
LiquidBounce | 9 | 62.5 | 24 | 182 | 49(5.4x) | 47.8
MyExpenses | 18 | 102.6 | 42.7 | 228.1 | 103.3(5.7x) | 84.7
NightX-Client | 6.4 | 34.2 | 7 | 46.3 | 23.1(3.6x) | 33.2
RootEncoder | 15.6 | 90.5 | 14.9 | 87.0 | 26.8(1.7x) | 46.0
SeriesGuide | 7.3 | 41.6 | 7.4 | 37.7 | 17.5(2.4x) | 40.0
simbrain | 10.9 | 86.3 | 8.5 | 59.6 | 31.4(2.9x) | 57.7
SkyHanni | 21.9 | 117.1 | 6.5 | 42.1 | 17.2 | 90.3
SkytilsMod | 17.9 | 102.9 | 10.3 | 194.5 | 31.2(1.7x) | 35.6
tasks | 11.7 | 65.4 | 11.1 | 66.1 | 35.6(3.0x) | 49.1
wire | 1.6 | 8.5 | 1.7 | 9.3 | 3.8(2.4x) | 39.4

###  4.2. Maintenance Cost in Kotlin-Java Projects

Recent studies on multi-language systems have revealed that the interface
between two languages is vulnerable and susceptible to bugs, often resulting
in increased maintenance costs for fixing these issues (Li et al., 2023a,
2022, b). This raises the question of whether the interface between Kotlin and
Java faces similar challenges. We investigated this question to gain a better
understanding of Kotlin-Java interactions and the associated challenges.

For each project, utilizing the dependency information got in RQ1 (see Section
4.1), we extracted the paths of Kotlin or Java source files involved in
Kotlin-Java dependencies, denoted as Paths(kt/java). Subsequently, we
traversed each project’s git commits and matched each modified file path of a
commit with Paths(kt/java). If a match was found, we incremented
#commit(aFile) by 1 and added the added and deleted lines of code (LOC) to
#LOC(aFile). Similarly, we calculated #commit and #LOC for Java or Kotlin
source files participating only in Java-Java or Kotlin-Kotlin interactions.

Table 5 presents the average LOC and commits for different types of files in
each project. The first two columns denote the average commit counts and LOC
for Kotlin source files that only interact with other Kotlin source files. The
middle two columns denote the average commit counts and LOC for Java source
files that only interact with other Java source files. The last two columns
denote the average commit counts and LOC for Kotlin source files that interact
with Java source files.

Comparing the first column with the second-to-last column, we observe that in
17 out of 23 projects (highlighted in blue), the average number of commits for
Kotlin source files participating in Kotlin-Java interactions is significantly
larger than for Kotlin source files not participating in Kotlin-Java
interactions. The number in the parentheses denotes the ratio of these two
commit counts. For example, in the husi project, the average number of commits
(23.7) for Kotlin source files participating in Kotlin-Java interactions is
6.1 times of that (3.9) for Kotlin source files not participating in Kotlin-
Java interactions. On average across all 23 projects, Kotlin source files
participating in Kotlin-Java interactions have 2.5 times more commits than
Kotlin source files not participating in Kotlin-Java interactions.

However, as observed from Table 5, the LOC for Kotlin source files
participating in Kotlin-Java interactions show no significant difference from
Kotlin source files not participating in Kotlin-Java interactions. Only in
these four projects (highlighted in blue in the last column) Kotlin source
files participating in Kotlin-Java interactions have more LOCs on average.
Furthermore, we conducted a t-test for these columns, and the t-test results
between column #Avg_Cmt_K and #Avg_Cmt_Kj indicate a statistically significant
difference at a 95% confidence level (df = 22, p-value = 0.016). Such results
support the alternative hypothesis that #Avg_Cmt_Kj is significantly greater
than #Avg_Cmt_K. However, the t-test results indicate no statistically
significant difference between #Avg_LOC_K and #Avg_LOC_Kj (df = 22, p-value =
0.125). We conjecture this is because Kotlin source files participating in the
interactions are often committed to modify only a small amount of code related
to the facade, such as method calls, field access, parameter changes, etc.

To answer RQ2, the average number of commits and LOC for 23 open-source
Kotlin-Java projects indicate that Kotlin source files participating in
Kotlin-Java interactions tend to have more commits but not more LOCs. On
average across all 23 projects, Kotlin source files involved in Kotlin-Java
interactions have 2.5 times more commits compared to Kotlin source files that
do not participate in Kotlin-Java interactions.

###  4.3. Common Mistakes in Kotlin-Java Interactions

The results of RQ2 reveal that source files participating in Kotlin-Java
interactions undergo more commits and are prone to changes. To answer RQ3, we
delve into the details of why certain Kotlin-Java interactions are
problematic. Following the approach described in Section 2.2, we identified
common mistakes in Kotlin-Java problematic interactions.

Table 6. Locate Problematic Kotlin-Java Commits All commits | 83792
---|---
f1: A commit’s comment contains words ‘fix’, ‘bug’, ‘issue’ or ‘exception’ | 5137
f2: A commit’s modified files are participated in Kotlin-Java interactions | 1314
Manual Inspection: confirmed commits to fix problematic Kotlin-Java interactions | 103

Table 6 presents the data in the process of locating commits involving
problematic Kotlin-Java interactions. Initially, there were 83,792 commits
among these projects. After filtering commits with comments containing the
words ’fix’, ’bug’, ’issue’ or ’exception’, there were 5,137 remaining
commits. These 5,137 commits were compared with the dependency graphs of the
latest version, resulting in 1,314 commits with modified files participating
in Kotlin-Java interactions. Finally, we manually inspected these 1,314
commits and confirmed 103 commits containing fixes for problematic Kotlin-Java
interactions. After discussion among three developers, we classified 98 of
these 103 problematic Kotlin-Java interactions into 7 categories according to
the issue and fixing strategies. Table 7 lists these categories and their
occurrences. In the following, we provide an example for each of these 7
categories.

Table 7. Common Mistakes in Kotlin-Java Interactions Common Mistake Category | Occurrence
---|---
Java Return Value NPE | 47
Java Invoke NPE | 21
Kotlin Wrong Not Null Assertion | 12
Call Chain NPE | 9
Kotlin Inherit Java Nullability Inconsistency | 5
Immutable Collection Conversion | 3
Overuse Java Optional in Kotlin code | 1
Other | 5
Total | 103

####  4.3.1. Java Return Value NPE (NullPointerException): fix by adding Null-
safe Operator for returned values from Java

This is the most common mistake we observed among the 103 problematic
interactions. When Kotlin code calls a Java method, the Kotlin compiler will
not be able to determine the nullability of the return value if the Java
method does not indicate the nullability of the return value with annotations
such as @NotNull or @Nullable. If Kotlin code accesses a variable whose
nullability is unknown, a NullPointerException (NPE) may get triggered.

Figure 3. Kotlin Add Null-Safe Operator to Fix NPE

Figure 3 shows an example of this mistake in commit
2cd4ca1222https://github.com/hannibal002/SkyHanni/commit/2cd4ca1 in the
SkyHanni project. The code marked in red attempts to call the method
getCanonicalName() in the Java class ‘Class’ and assumes that the returned
value from this method is not NULL. However, at runtime this method returns a
NULL and the red line throws a NPE. As stated in the commit comment, the
commit aims to “fix an NPE in ReflectionUtils.shPackageName”. It added the
Null-Safe Operator ? to the returned value of the getCanonicalName() method.
In this way, the Null-Safe Operator ? performs a NULL check on the returned
value shown in the lime color. If it is NULL, it stops the process without
proceeding to the next call.

####  4.3.2. Java Invoke NPE: fix by clarifying Nullability on Java code

This issue is similar to the previous one but differs in the error location
and fixing strategy. When developing a Kotlin-Java system, adding appropriate
nullable or non-nullable annotations (@NotNull or @Nullable) to Java’s public
API will enable modern IDEs to alert developers its nullability at the time of
invocation and provide stricter code checking during compilation. Without
annotations on parameters of Java’s public API, Kotlin code is unable to
determine the required nullability of parameters and an inappropriate API call
will result in a NPE.

Figure 4 shows commit f240ed6333https://github.com/ant-druha/intellij-
powershell/commit/f240ed6 from the intellij-powershell project, which is a
good example of the importance of Java nullability annotation when interacting
with Kotlin. To “fix exception thrown when plugin is enabled but no powershell
is found in the path” as stated in the commit comment, @NotNull annotation was
added to the powerShellExecPath Java method (shown in lime color) and Kotlin
code which invoked this method was also changed accordingly.

Figure 4. Java API Add Annotation to Fix NPE

####  4.3.3. Kotlin Wrong Not Null Assertion: fix by modifying non null
assertion operator

When a developer is confident that the returned value of a method or a
property is non-null at all times, they apply a not null assertion !! operator
in Kotlin code to emphasize its non-null nature. Such assertions offer
significant convenience in subsequent code writing, eliminating the need for
NULL checks and enhancing logical flow. However, not-null assertions also pose
risks. If applied to a value whose nullability is not entirely determinable,
an NPE may still occur at runtime if the value turns out to be null,
potentially affecting a substantial portion of the subsequent code.

Figure 5. Kotlin Not Null Assertion throws NPE

Figure 5 depicts commit
83dc35e444https://github.com/square/wire/commit/83dc35e from the wire project.
A not null assertion !! operator was placed on the entries variable. However,
this code throws a NPE at runtime because it fails to fully consider the
nullability of the entries variable. The commit message “fix: options entries
can be null for files imported from external jars” verified this observation
and the not null assertion !! operator was changed to the null-safe Operator ?
in this commit.

####  4.3.4. Call Chain NPE: fix by adding null safe operation or add
annotation on method signature

In interactions between Kotlin and Java, we frequently observe that Kotlin
code performs method chain calls on Java methods. If a method in the sequence
returns a null value and the subsequent method call relies on this result
without checking, it can lead to an NPE. The commit
79c9792555https://github.com/ant-druha/intellij-powershell/commit/79c9792 in
the intellij-powershell project demonstrates an example of this case.

⬇

1/* SyntheticPowerShellCodeBlock.kt */

2import com.intellij.lang.ASTNode

3import com.intellij.psi.formatter.java.LeafBlock

4

5 private fun isRParenth(block: Block?): Boolean {

6 return block is LeafBlock && block.node.elementType === PowerShellTypes.RP

7 }

In this example, a method in the SyntheticPowerShellCodeBlock Kotlin Class is
importing and depending on Java classes ASTNode and LeafBlock. The code in
Line 6 shows a calling chain to LeafBlock and ASTNode through
block.node.elementType in this method. If the node attribute is not initiated
in block object, the subsequent call .elementType will throw a NPE. In this
commit, developers patched this bug by modifying it to
block.node?.elementType. The null safe operator ? in block.node? performs a
NULL check on the node object and allow for a safe call. If it is a null,
block.node?.elementType will return a null without calling .elementType.

There are two ways to fix this issue. One is to use null safe operator just
like in this example to allow the returned value being nullable. The other is
to specify the return value of each method nullable by adding annotation along
with the method’s signature and let IDEs handle it at the compilcation.

####  4.3.5. Kotlin Inherit Java Nullability Inconsistency: fix by ensuring
parent-child API consistent

This scenario happens when a Kotlin class inherits a Java class and overrides
the parent methods, the nullability of parameters in the overridden methods is
inconsistent between the parent and child class. This is not a problem in
Kotlin-Kotlin or Java-Java interactions as the type consistency is manually
enforced in modern IDEs. However, the nullability consistency is not enforced
for Kotlin-Java interactions by modern IDEs so developers need to manually
check it. The commit da56686666https://github.com/grpc/grpc-
kotlin/commit/da56686 in the grpc-kotlin project shows an example and how
developers were addressing it.

As we can see from the following code, DeclarationSubject class is written in
Kotlin and it extends the Subject Java class. The second parameter
Declarations in the child Kotlin class is not null while the parent Java class
Subject specify the second parameter actual as @Nullable. There exists an
inconsistency between these two constructor methods, though this does not
cause any problems before version 1.1.3 as the callers of these constructors
in the Factory interface does not specify @Nullable in its parameter too.

⬇

1 /** Subject.java */

2 protected Subject(FailureMetadata metadata, @Nullable Object actual) {

3 this(metadata, actual, /* typeDescriptionOverride= */ null);

4 }

⬇

1 /** DeclarationsSubject.kt */

2 class DeclarationsSubject(failureMetadata: FailureMetadata, private val
actual: Declarations): Subject(failureMetadata, actual) {...}

3 // This calls the Factory interface in Subject.

4 val declarationsSubjectFactory: Subject.Factory<DeclarationsSubject,
Declarations> =

5 Subject.Factory(::DeclarationsSubject)

However, in Version 1.1.5, the Factory interface in Subject class added
@Nullable annotations to its parameter ActualT actual as shown below. When the
grpc-kotlin project upgraded the Subject’s package – com.google.truth:truth–,
from Version 1.1.3 to 1.1.5, the Factory interface requires a nullable type
for createSubject’s second parameter specifically while DeclarationSubject is
not. This results in a complication error.

⬇

1 /** Factory in Subject.java in version 1.1.3. */

2 public interface Factory<SubjectT extends Subject, ActualT> {

3 /** Creates a new {@link Subject}. */

4 SubjectT createSubject(FailureMetadata metadata, ActualT actual);

5 }

6 /** Factory in Subject.java in version 1.1.5. */

7 public interface Factory<SubjectT extends Subject, ActualT> {

8 /** Creates a new {@link Subject}. */

9 SubjectT createSubject(FailureMetadata metadata, @Nullable ActualT actual);

10 }

To fix this error, developers added the null safe operator ? in the child
Kotlin class DeclarationSubject, allowing the second parameter to be nullable.
From this example, we can conclude that, although the inconsistency would not
result in compilation errors within the DeclarationSubject class itself, it
can arise potential issues from a third class’ calling. It is necessary to
make sure that Kotlin-Java parent-child overridden methods strictly follow the
same nullability type. Furthermore, this is also a violation of Liskov
Substitution Principle, which requires a subtype should be substitutable for
its supertype.

####  4.3.6. Immutable Collection Conversion: fix by creating a defensive copy
of Java collections

In Kotlin, collections can be categorized as modifiable, such as MutableList
or MutableSet, and unmodifiable types, such as List or Set. If Java code calls
collections from Kotlin code, modern IDEs ensure that proper methods of
collections are invoked, meaning that mutation methods like add() or remove()
in Java cannot be applied to an unmodifiable Kotlin collection.

However, if Kotlin code is accessing collections from Java code, the
mutability of the collections is unknown to the Kotlin side. This is because
unmodifiable collections in Java act as a wrapper around existing modifiable
collections. Therefore, public methods such as add, remove, and update in Java
modifiable collections can also be called on Java unmodifiable collections.
This presents a challenge on the Kotlin side because the mutability of
collections returned from Java is not known.

Figure 6 illustrates an example of this issue in the commit
a8cf6eb777https://github.com/square/wire/commit/a8cf6eb of the wire project.
The getFromBuilder method utilizes Java’s reflection mechanism and returns an
object with a java.util.Map type. Prior to this commit, this Map object was
mistakenly treated as a Kotlin MutableMap. Since the mutability of Java’s
collections is not inherently recognized in Kotlin, developers introduced a
check for this Map object in this commit. If the object is confirmed to be a
MutableMap, records are added to it directly. If it is not a MutableMap, a
defensive copy of the map is created first, and then the records are put into
the copied map. If the object cannot be cast to either a MutableMap or a Map,
an exception is thrown. Although this approach solves the problem, we do not
recommend using obj is MutableMap in JVM to check its mutability. The good
practice is to assume that all collections of unknown mutability are immutable
and create a defensive copy (you, [n. d.]).

Figure 6. Immutable Collection Conversion

####  4.3.7. Overuse Java Optional in Kotlin code: fix by leveraging safe
check mechanisum in Kotlin

One key feature of Kotlin is to eliminate the danger of null references by
leveraging nullable types and non-nullable type. Compared to Kotlin, Java does
not have such feature and thus it needs other techniques such as Optional to
check whether a value is null or not. Optional is a container class introduced
in Java 8 and provides a way to represent optional values without using null
references, thereby helping to avoid common programming pitfalls associated
with null values. The Optional class includes methods like isPresent(), get(),
ifPresent(), and orElse(), which enable developers to check value presence and
absence and to handle cases where a value might be missing.

We observed a case that Kotlin code overuse Java Optional, instead of
leveraging Kotlin’s own typing system. The commit
b9853c6888https://github.com/Netflix/dgs-framework/commit/b9853c6 in the dgs-
framework demonstrates an example, with its commit comment “eliminate some
unnecessary usage of Optional”.

Figure 7. Overuse Java Optional in Kotlin Code

Figure 7 illustrates a portion of the code modifications made to the
DgsGraphQLMetricsInstrumentation Kotlin file. Previously, the Optional class
was extensively utilized to encapsulate four attributes: queryComplexity,
operation, operationName, and querySignature. Within the tags method, the
map() and orElse() methods from the Optional class were used to check the
nullability of the wrapped objects. However, in this commit, developers opted
to removed all this Optional wrapping and leveraged Kotlin’s null mechanisms.
For instance, as shown in the last two lines of Figure 7, the null safe
operator ? was appended to querySignature to verify its nullability, thereby
replacing the need for the map() method from the Optional class. Overuse of
the Optional class not only consumes additional memory and can negatively
affect system performance, but it may also complicate code comprehension. We
strongly suggest practitioners to examine the overuse of Optional in Kotlin
code.

To answer RQ3, we conducted a manual inspection of 103 cases involving Kotlin-
Java interactions, which had already led to system errors or incurred
maintenance costs. Through these inspections, we identified 7 categories of
common mistakes along with corresponding fixing strategies. We believe that
these categorized cases can serve as a taxonomy and assist developers in
correctly handling Kotlin-Java interactions.

##  5\. Discussions

###  5.1. Analysis of Results

The findings of RQ1 have demonstrated the interoperability between Kotlin and
Java. Unlike other cross-language systems that rely on compiled code, the
dependencies between Kotlin and Java code are more direct and span across
entire systems. Consequently, this leads to more cross-language interfaces and
presents greater challenges for Kotlin-Java interactions. The results of RQ2
indicate that source files involved in Kotlin-Java interactions undergo more
commits than those exclusively involved in a single language. It demonstrates
that Kotlin-Java interfaces are inherently more active, just like other cross-
language interfaces, even though Kotlin and Java can coexist within the same
IDEs and their interaction mechanism is different from other cross-language
systems.

The manual inspections of 103 cases in RQ3 reveal specific 7 categories of
mistakes within Kotlin-Java interactions. In contrast to Python-C interfaces,
which are known to suffer from vulnerabilities (Li et al., 2022), 89 out of
103 problematic interactions between Kotlin and Java are related to
NullPointerExceptions (NPEs). Despite Kotlin being known for its better null
safety mechanism compared to Java, the interface between Kotlin and Java still
experiences NPEs. Other mistakes, such as “Immutable Collection Conversion”
and “Overuse of Java Optional in Kotlin”, result from unfamiliarity with
Kotlin documentation. It is also surprising that we did not find any exception
handling mistakes in the Kotlin-Java interactions, despite Java and Kotlin
having different exception catching rules. This can be attributed to modern
IDEs’s checking in the compilation process.

###  5.2. Implications

To Software Practitioner: Although Kotlin and Java can interact smoothly at
the code level, common interaction mistakes still exist that may not be
captured by modern IDEs. The identified categories of interaction mistakes and
their fixing strategies can serve as a valuable reference, complementing the
Kotlin-Java interoperability guide from Android (and, [n. d.]).

To Researchers: Different cross-language interactions may suffer from various
problems. Conducting empirical studies to identify problematic interactions
with associated errors and maintenance costs is key to pinpointing them
accurately. For Kotlin-Java interactions, there is a high demand for research
and tools that can automatically detect and fix these issues.

###  5.3. Threats to Validity

One threat is the accuracy of our dependency extraction tool. DependExtractor
is based on the Kotlin compiler and dependency types are defined according to
previous research. Though we added test cases and manually validate the tool
in several small projects, we cannot guarantee that it is 100% accurate for
extracted dependencies. We plan to conduct more tests and validations of the
tool in the future work.

Another threat is that we only investigated 23 real-world projects with Kotlin
as the primary languages. It is possible that additional categories of
problematic Kotlin-Java or Java-Kotlin interactions may be discovered in other
projects. Exploring this possibility remains part of our future work.

##  6\. Related Work

In this section, we discuss related research to our work from two
perspectives: empirical studies on Kotlin-Java projects and code dependency
extraction in cross-language systems.

###  6.1. Empirical Studies on Kotlin-Java Projects

Since the introduction of Kotlin, various empirical studies have been
conducted to understand Kotlin-Java projects. Martinez and Mateus investigated
why developers migrate Android applications from Java to Kotlin (Martinez and
Mateus, 2021). They also examined the adoption, usage, and evolution of Kotlin
features in Android development (Mateus and Martinez, 2020). Nakamura et al.
conducted a performance study of Kotlin and Java programs using bytecode
analysis (Nakamura et al., 2024). Ardito et al. compared the effectiveness of
Kotlin versus Java in Android app development tasks (Ardito et al., 2020).
Flauzino et al. compared code smells between Java and Kotlin (Flauzino et al.,
2018). Bose et al. compared Java versus Kotlin in terms of null safety,
exception handling, and other aspects (Bose et al., 2018).

While previous studies have compared various characteristics of Java with
Kotlin, our study offers an empirical investigation into how Kotlin actually
interacts with Java code. Despite the availability of documentation from
Google and Android guiding Kotlin-Java interaction, to our knowledge, our
study is the first to examine Kotlin-Java interactions in real-world projects.
Our findings reveal that while Kotlin and Java demonstrate great
interoperability and interact with each other extensively across systems,
challenges and issues persist in such interactions. The recurring patterns
identified in problematic Kotlin-Java interactions in this paper deserve
special attention from developers, especially Kotlin developers.

###  6.2. Code Dependencies Extraction

The dependency relations among entities in the source code form the
foundations of software analysis (Mo et al., 2019; Cui et al., 2019; Xiao et
al., 2022). Existing techniques often rely on static code analysis to capture
and model extract dependency relations from source code such as Java, Python
and C/C++ (Jin et al., 2024; Filgueira and Garijo, 2022; Molina et al., 2021;
Savić et al., 2014). Various tools such as Structure 101 (str, [n. d.]),
Understand (und, [n. d.]), and DV8 (dv8, [n. d.]) have been developed to
support the extraction of dependency relations among entities in large-scale
software projects.

While techniques and tools for extracting dependencies among code entities
within single programming language are relatively mature, the extraction of
dependencies among multiple programming languages remains largely unexplored.
With advancements in modern platforms, it has become common to utilize
multiple programming languages within the same system to achieve enhanced
performance and scalability (Mayer et al., 2017; Tomassetti and Torchiano,
2014). However, this also increases the complexity of systems, posing
challenges for extracting dependencies in such heterogeneous langauge
environments. A recent systematic review reveals that traditional code
analysis tools face challenges in these cross-language systems (Latif et al.,
2023). A study also highlights high-risk vulnerabilities between Python and C
interfaces, proposing symbolic dependence analysis to detect such
vulnerabilities (Li et al., 2022). As a complement to the above studies, our
study proposed to extract code dependencies between Java and Kotlin code and
further detect problems in Kotlin and Java interactions.

##  7\. Conclusions

In this paper, we conducted an empirical study of Kotlin-Java interactions in
23 real-world projects. Our results demonstrate that Kotlin and Java interact
frequently across the entire systems, confirming the extensive
interoperability of Kotlin and Java. However, our study also reveals that
source files involved in such cross-language systems have more commits
compared to source files involved in only a single language.

Furthermore, we identified seven common mistakes in Kotlin-Java interactions,
along with their corresponding fixing strategies. Unlike code smells, which
are detected by rules and often have high false positives, these mistakes were
extracted from commits in Git repositories and have been shown to require more
maintenance effort. We believe that recognizing these identified mistakes in
Kotlin-Java interactions can assist developers in effectively improving such
cross-langauage interactions.

## References

  * (1)
  * dep ([n. d.]) [n. d.].  Depends.  https://github.com/multilang-depends/depends/
  * dv8 ([n. d.]) [n. d.].  DV8.  https://archdia.com/
  * and ([n. d.]) [n. d.].  Kotlin-Java Interop Guide from Android.  https://developer.android.com/kotlin/interop/
  * str ([n. d.]) [n. d.].  Structure101.  https://structure101.com/
  * und ([n. d.]) [n. d.].  Understand.  https://scitools.com/
  * you ([n. d.]) [n. d.].  YouTrack-kt-39635.  https://youtrack.jetbrains.com/issue/KT-39635/UnsupportedOperationException-with-list-casted-to-MutableList#focus=Comments-27-4275157.0-0
  * Ardito et al. (2020) Luca Ardito, Riccardo Coppola, Giovanni Malnati, and Marco Torchiano. 2020.  Effectiveness of Kotlin vs. Java in android app development tasks.  _Information and Software Technology_ 127 (2020), 106374.
  * Bose et al. (2018) Subham Bose, Madhuleena Mukherjee, Aditi Kundu, and Madhurima Banerjee. 2018.  A comparative study: java vs kotlin programming in android application development.  _International Journal of Advanced Research in Computer Science_ 9, 3 (2018), 41–45.
  * Campbell et al. (2013) John L Campbell, Charles Quincy, Jordan Osserman, and Ove K Pedersen. 2013.  Coding in-depth semistructured interviews: Problems of unitization and intercoder reliability and agreement.  _Sociological Methods & Research_ 42, 3 (2013), 294–320.
  * Cui et al. (2019) Di Cui, Ting Liu, Yuanfang Cai, Qinghua Zheng, Qiong Feng, Wuxia Jin, Jiaqi Guo, and Yu Qu. 2019.  Investigating the impact of multiple dependency structures on software defects. In _Proceedings of the 41st IEEE/ACM International Conference on Software Engineering (ICSE)_. IEEE, 584–595.
  * Filgueira and Garijo (2022) Rosa Filgueira and Daniel Garijo. 2022.  Inspect4py: A knowledge extraction framework for python code repositories. In _Proceedings of the 19th International Conference on Mining Software Repositories (MSR)_. IEEE, 232–236.
  * Flauzino et al. (2018) Matheus Flauzino, Júlio Veríssimo, Ricardo Terra, Elder Cirilo, Vinicius HS Durelli, and Rafael S Durelli. 2018.  Are you still smelling it? A comparative study between Java and Kotlin language. In _Proceedings of the 7th Brazilian Symposium on Software Components, Architectures, and Reuse (SBCARS)_. IEEE, 23–32.
  * Jin et al. (2019) Wuxia Jin, Yuanfang Cai, Rick Kazman, Qinghua Zheng, Di Cui, and Ting Liu. 2019.  ENRE: a tool framework for extensible eNtity relation extraction. In _Proceedings of the 41st IEEE/ACM International Conference on Software Engineering: Companion (ICSE-Companion)_. IEEE, 67–70.
  * Jin et al. (2024) Wuxia Jin, Shuo Xu, Dawei Chen, Jiajun He, Dinghong Zhong, Ming Fan, Hongxu Chen, Huijia Zhang, and Ting Liu. 2024.  PyAnalyzer: An Effective and Practical Approach for Dependency Extraction from Python Code. In _Proceedings of the 46th IEEE/ACM International Conference on Software Engineering (ICSE)_. ACM, 1–12.
  * Latif et al. (2023) Saira Latif, Zaigham Mushtaq, Ghulam Rasool, Furqan Rustam, Naila Aslam, and Imran Ashraf. 2023.  Pragmatic evidence of cross-language link detection: A systematic literature review.  _Journal of Systems and Software_ (2023), 111825.
  * Li et al. (2022) Wen Li, Jiang Ming, Xiapu Luo, and Haipeng Cai. 2022.  PolyCruise: A cross-language dynamic information flow analysis. In _Proceedings of the 31st USENIX Security Symposium (USENIX Security)_. USENIX, 2513–2530.
  * Li et al. (2023b) Zengyang Li, Sicheng Wang, Wenshuo Wang, Peng Liang, Ran Mo, and Bing Li. 2023b.  Understanding bugs in multi-language deep learning frameworks. In _Proceedings of the 31st IEEE/ACM International Conference on Program Comprehension (ICPC)_. IEEE, 328–338.
  * Li et al. (2023a) Zengyang Li, Wenshuo Wang, Sicheng Wang, Peng Liang, and Ran Mo. 2023a.  Understanding Resolution of Multi-Language Bugs: An Empirical Study on Apache Projects. In _Proceedings of the 17th ACM/IEEE International Symposium on Empirical Software Engineering and Measurement (ESEM)_. IEEE, 1–11.
  * Martinez and Mateus (2021) Matias Martinez and Bruno Gois Mateus. 2021.  Why did developers migrate android applications from java to kotlin?  _IEEE Transactions on Software Engineering_ 48, 11 (2021), 4521–4534.
  * Mateus and Martinez (2020) Bruno Gois Mateus and Matias Martinez. 2020.  On the adoption, usage and evolution of Kotlin features in Android development. In _Proceedings of the 14th ACM/IEEE International Symposium on Empirical Software Engineering and Measurement (ESEM)_. ACM, 1–12.
  * Mayer et al. (2017) Philip Mayer, Michael Kirsch, and Minh Anh Le. 2017.  On multi-language software development, cross-language links and accompanying tools: a survey of professional software developers.  _Journal of Software Engineering Research and Development_ 5 (2017), 1–33.
  * Mo et al. (2019) Ran Mo, Yuanfang Cai, Rick Kazman, Lu Xiao, and Qiong Feng. 2019.  Architecture Anti-patterns: Automatically Detectable Violations of Design Principles.  _IEEE Transactions on Software Engineering_ 47, 5 (2019), 1008–1028.
  * Molina et al. (2021) Jacinto Molina, Xue Qin, and Xiaoyin Wang. 2021.  Automatic extraction of code dependency in virtual reality software. In _Proceedings of the 29th IEEE/ACM International Conference on Program Comprehension (ICPC)_. IEEE, 381–385.
  * Nakamura et al. (2024) Hayataka Nakamura, Atsuya Sonoyama, Takeshi Kamiyama, Masato Oguchi, and Saneyasu Yamaguchi. 2024.  Performance Study of Kotlin and Java Programs with Bytecode Analysis.  _Journal of Information Processing_ 32 (2024), 380–395.
  * Savić et al. (2014) Miloš Savić, Gordana Rakić, Zoran Budimac, and Mirjana Ivanović. 2014.  A language-independent approach to the extraction of dependencies between source code entities.  _Information and Software Technology_ 56, 10 (2014), 1268–1288.
  * Tomassetti and Torchiano (2014) Federico Tomassetti and Marco Torchiano. 2014.  An empirical assessment of polyglot-ism in GitHub. In _Proceedings of the 18th International Conference on Evaluation and Assessment in Software Engineering (EASE)_. ACM, 1–4.
  * Xiao et al. (2022) Lu Xiao, Yuanfang Cai, Rick Kazman, Ran Mo, and Qiong Feng. 2022.  Detecting the Locations and Predicting the Costs of Compound Architectural Debts.  _IEEE Transactions on Software Engineering_ 48, 9 (2022), 3686–3715.