Kotlin has 3 keywords for access: public, private and protected. Do they mean the same thing as in Java, or are there differences? Also, is internal the same as package private? I keep reading about "modules" in Kotlin, and I'm not sure if that's just another word for "package".
Kotlin's access modifiers do not always mean the same thing as in Java. For example, Kotlin allows protected members in interfaces while Java does not.
Modules are compile-time only entities. They group source files and declare dependencies for them (binary libraries and other modules). A module is a unit of compilation, i.e. all of its files are compiled together (in fact there is file-by-file incremental compilation, but its effect must be the same as re-compiling the whole module).
For example, each Maven pom implicitly declares a module, and IDE has modules in the Project View and Project Structure.
Related
I've read the Kotlin doc (https://kotlinlang.org/docs/packages.html), and I understood that, when importing a package, the package name does not need to match the folder's path that stores the package (unlike what happens in Java).
I don't have issues creating a package and importing it into other classes.
What I'd like to understand, is how the compiler can find the file to import?
For example:
if a file import animals.mammals.cats.* :
import animals.mammals.cats.*
...
the entities to import do not need to be stored in the file /animals/mammals/cats.kt, as long as the package name is "animals.mammals.cats":
package animals.mammals.cats
...
This Kotlin file could be stored in src/animals/kittens for example.
In other words, how import can locate the file/s to load since the package name does not help?
Thanks!
TL;DR: the compiler is given the paths to all files to compile and to all dependencies, and therefore knows about all available packages and the declarations they contain.
First, note that the import statement itself is not really the most important. It's just a convenient syntax to avoid having to specify the package everywhere throughout the file. But technically you don't need to import anything to be able to use declarations from outside the current file - you can just use their fully qualified name (a.k.a FQN) which is the package name + . + the name of the declaration.
Now, on to your question. When you run the compiler, you provide the paths to the complete set of files to be compiled at the same time: you compile a module, not a single file. Therefore, it has access to all declarations in all those files and maintains its own data structures about the available classes and top-level functions, and all symbols in general. So it can store and find declarations using just their FQN. (DISCLAIMER: I'm no expert and I don't actually know how it's done internally, but I'm just guessing that conceptually it's like storing a big mapping between FQN and the information about the corresponding declaration.)
If the declaration you use is not in the set of files being compiled, it must be in one of your dependencies. You can tell the compiler about the available dependencies by specifying the list of jars containing their already compiled classes. This list of all classes available at compile time is called the compile classpath. This is why the tool you use to build your project (for instance, Gradle or your IDE) needs to know about those dependencies, so it can put their declarations on the compile classpath when calling the compiler for you. Then, just like declarations that are being compiled, the ones from the compile classpath can be easily looked up by the compiler (the path has been given to the compiler as an argument).
Now, when you actually run your compiled program, at least on the JVM, the classes required must be placed on the runtime classpath - a set of classes given to the java program. Finding those declarations while the program runs is done by classloaders. There are multiple classloaders, organized in a hierarchy, but there is no need to go into details here. Basically, each time a class is used for the first time while your program is running, one classloader will be asked to load that class into memory. There are different implementations of classloaders, but one of the most common is the URLClassLoader which is given the URLs of some jars that contain classes, and knows how to read classes from these jars into memory on-demand.
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.
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
I'm trying to use JavaFX in my android device, with the help of javafxports.
I used the XStream to parse some XML file in my program.
When i compile them, the javafxports outputs the following warnings:
Note: there were 9 classes trying to access annotations using reflection.
You should consider keeping the annotation attributes
(using '-keepattributes *Annotation*').
(http://proguard.sourceforge.net/manual/troubleshooting.html#attributes)
Note: there were 32 classes trying to access generic signatures using reflection.
You should consider keeping the signature attributes
(using '-keepattributes Signature').
(http://proguard.sourceforge.net/manual/troubleshooting.html#attributes)
Note: there were 56 unresolved dynamic references to classes or interfaces.
You should check if you need to specify additional program jars.
(http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclass)
Note: there were 3 class casts of dynamically created class instances.
You might consider explicitly keeping the mentioned classes and/or
their implementations (using '-keep').
(http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclasscast)
Note: there were 39 accesses to class members by means of introspection.
You should consider explicitly keeping the mentioned class members
(using '-keep' or '-keepclassmembers').
(http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclassmember)
Note: you're ignoring all warnings!
The output .apk can be installed and run until it calls the xstream classes to read annotations in my classes. The reason is actually described in the warnings.
So my question is, how can i disable the proguard when generating .apk, or send it a custom proguard.pro configuration.
And my build.gradle is almost the same as that in the helloworld example.
Thanks.
Official docs on visibility modifiers in Kotlin say that package-level elements marked private are be visible only in the module in which they are declared.
So class A declared in Module1.kt isn't visible in Module2.kt. But if I try to add to Module2.kt it's own class A I get the Redeclaration: A error.
Since I can't access in Module2.kt to Module1's A class, why isn't the name A free to use?
"A module is a set of Kotlin files compiled together" (Visibility Modifiers - Kotlin Programming Language).
In your example, Module1.kt and Module2.kt are separate source files and despite their names they are not necessarily part of separate modules:
If they are compiled together then they are part of the same module.
If they are compiled separately from one another then they will be part of different modules and each can define their own private class A.
Keep in mind that visibility is different from identity. Even if a class is not visible elsewhere it doesn't mean that it does not exist. Loading multiple class declarations with the same fully-qualified name can (and likely will) cause issues at run-time.