What does "Symbol" mean in KSP - kotlin

Currently I am studying on KSP(Kotlin Symbol Processing), and I am curious about what does "Symbol" mean in KSP.
When it comes to comparing with KAPT, it says "To run Java annotation processors unmodified, KAPT compiles Kotlin code into Java stubs that retain information that Java annotation processors care about. To create these stubs, KAPT needs to resolve all symbols in the Kotlin program."
I don't know what does "all symbols in the Kotlin program" exactly mean?

I understand "symbols" as declarations of interfaces, classes, functions, properties, etc. It doesn't include the body or the code itself, only the API, items that are visible to others.
This term is not specific to Kotlin. I can't find any definition of "symbols" on Wikipedia, but for example native libraries also contain symbol tables.
In this specific context it means that KAPT has to create a full list of all such symbols in Kotlin code and generate their equivalents in Java, so annotation processors could work on them. This is pretty wasteful as we recreate Kotlin code structure in Java just to throw it away seconds later and replace with true compiled code.

Related

Why strip() is deprecated in Kotlin and what should I use instead?

For String.strip() I get warning 'strip(): String!' is deprecated. This member is not fully supported by Kotlin compiler, so it may be absent or have different signature in next major version"
Why is it? "strip" comes from Java String
What should I use?
First of all: String.strip() is a new function in Java 11. Kotlin targets JVM 6 by default, so I was unable to reproduce your issue at first, I got a compilation error. Using JVM 11 as target in Android Studio worked with your compiler warning.
Kotlin's string class (kotlin.String) is not the same as Java's string class (java.lang.String). The Kotlin type is however mapped to the Java type (quote):
Kotlin types such as List, MutableList, String, CharSequence etc. are all compiled to their java equivalents, and thus any runtime checks will not be able to distinguish between them. At compile-time, however, they are distinct types with different sets of members. In particular, the Kotlin types do not have all members that the corresponding Java types have. They have those listed in the Kotlin std lib reference, as well as a few extra JVM specific ones (such as Collection.stream())
kotlin.String does not have a .strip() function. You are just "incidentally" calling java.lang.String.strip() which happens to be there in some target JVMs but not defined in Kotlin. If you look at the kotlin.String source in your IDE you can see it is not defined there.
The reason it is not there is because it was explicitly graylisted by the Kotlin team:
Some methods in JDK classes are undesirable in Kotlin built-ins (e.g. a lot of String methods or List.sort(), because there are Kotlin analogues with better signatures already defined).
.strip() does the same thing as kotlin.String.trim(), so use that instead.
Extended Reading
Extended Reading 2
The commit which put .strip() on the graylist

Are Kotlin lambdas the same as Java lambdas under the hood?

This is a follow up question of this answer.
But when the application hasn’t used lambda expressions before¹, even
the framework for generating the lambda classes has to be loaded
(Oracle’s current implementation uses ASM under the hood). This is the
actual cause of the slowdown, loading and initialization of a dozen
internally used classes, not the lambda expression itself
Ok, Java uses ASM to generate the classes on runtime. I found this and if I understood correctly, it is basically saying that Kotlin lambdas are compiled to pre-existing anonymous classes being loaded at runtime (instead of generated).
If I'm correct, Kotlin lambdas aren't the same thing as Java and shouldn't have the same performance impact. Can someone confirm?
Of course, Kotlin has built-in support for inlining lambdas, where Java doesn't. So many lambdas in Kotlin code don't correspond to any objects at runtime at all.
But for those that can't be inlined, yes, according to https://medium.com/#christian.c.carroll/exploring-kotlin-lambda-bytecode-8c2d15afd490 the anonymous class translation seems to be always used. Unfortunately the post doesn't specify the Kotlin version (1.3.30 was the latest available at that time).
I would also consider this an implementation detail which could change depending on Kotlin version at least when jvmTarget is set to "1.8" or greater; so there is no substitute to actually checking your own bytecode.

what is aptMode of kapt used for?

In the doc there are three values for the aptMode.
Is there any detail information about these values ?
What is the meaning of "stubs" ?
See https://blog.jetbrains.com/kotlin/2015/06/better-annotation-processing-supporting-stubs-in-kapt/ (stubs are described in the second paragraph, but the first one provides context):
The initial version of kapt worked by intercepting communication between annotation processors (e.g. Dagger 2) and javac, and added already-compiled Kotlin classes on top of the Java classes that javac saw itself in the sources. The problem with this approach was that, since Kotlin classes had to be already compiled, there was no way for them to refer to any code generated by the processor (e.g. Dagger’s module classes). Thus we had to write Dagger application classes in Java.
As discussed in the previous blog post, the problem can be overcome by generating stubs of Kotlin classes before running javac and then running real compilation after javac has finished. Stubs contain only declarations and no bodies of methods. The Kotlin compiler used to create such stubs in memory anyways (they are used for Java interop, when Java code refers back to Kotlin), so all we had to do was serialize them to files on disk.
And also this answer.
But now stubs are generated by default, you can explicitly disable this generation by using aptMode=apt or only generate stubs by using aptMode=stubs. I think they are primarily for use internally by build systems (e.g. Gradle), as described in https://www.bountysource.com/issues/38443087-support-for-kapt-for-improved-kotlin-support:
There's 4 steps.
kaptGenerateStubsKotlin:
run kotlinc with plugin:org.jetbrains.kotlin.kapt3:aptMode=stubs
kaptKotlin
run kotlinc with plugin:org.jetbrains.kotlin.kapt3:aptMode=apt
compileKotlin
run kotlinc regularly
compileJava
run javac with -proc:none and pass the generated sources from step 2.
These steps are slightly different with each minor version of kotlin so this will be interesting.

Why Kotlin blindly change internal classes into public in JVM?

As you know the private classes in Kotlin change to package-private under the hood and internals changed to the public.
unfortunately, this can lead to the known problem here.
if the compiler sees the usage of Kotlin internal classes when it wants to change it to the byte code, it can choose package-private for internal kotlin classes that didn't use outside of the package and choose public for others, so we can handle above problem on our own.
Or they can define another annotation such as #JvmPackagePrivate before internal classes to tell the compiler we want a package-private class in java.
Or they can do both.
The question is, why they don't solve this obvious problem with such an obvious solution?
Are they have another approach to solve this?
I just got acquainted with the Kotlin, so I think that I cant create lib for java with kotlin because when I create internal concrete classes, all client can see them outside of the library and its serious problem with kotlin. why they can't see this obvious problem??????
I want to mention that none of the answers in here solve this problem because of #JvmSynthetic and #JvmName just target the fun in kotlin, not classes and at the end they both visible even if they change the name of classes.
at last kotlin claims that it is completely interoperable with java but I think it's not right. better to say that it is 99 percent interoperable with java :)

What is the purpose of actual keyword in Kotlin

I noticed that some functions for coroutines are marked with actual keyword.
From documentation:
actual denotes a platform-specific implementation in multiplatform
projects
As I understood from documentation actual keyword is used for multiplatform projects and should work in pair with expect keyword.
Something like this:
Common module:
package org.jetbrains.foo
expect class Foo(bar: String) {
fun frob()
}
fun main(args: Array<String>) {
Foo("Hello").frob()
}
Corresponding module:
package org.jetbrains.foo
actual class Foo actual constructor(val bar: String) {
actual fun frob() {
println("Frobbing the $bar")
}
}
That case is clear.
But in package kotlinx.coroutines.experimental I noticed that some functions like launch or withContext are marked as actual but there are no expect functions in package.
So what is the purpose of actual keyword without expect?
The kotlinx.coroutines library actually makes use of multiplatform projects since it supports both the JVM and JS compilation targets.
You can find the common module here, and the specific expect declarations for the functions you've mentioned here.
While the source code in the other answer helped, I found this page (linked off of the page #jim-andreas mentioned in the comments above) was much more helpful.
Specifically, this passage:
If you're developing a multiplatform application that needs to access platform-specific APIs that implement the required functionality (for example, generating a UUID), use the Kotlin mechanism of expected and actual declarations.
With this mechanism, a common source set defines an expected
declaration, and platform source sets must provide the actual
declaration that corresponds to the expected declaration. This works
for most Kotlin declarations, such as functions, classes, interfaces,
enumerations, properties, and annotations.
The compiler ensures that every declaration marked with the expect keyword in the common module has the corresponding declarations marked with the actual keyword in all platform modules. The IDE provides tools that help you create the missing actual declarations.
Again, for more information, you can visit this page.