What packages/functions are imported by default in Kotlin? - kotlin

In Java the java.lang package is imported by default.
In kotlin a number of functions and classes are available without being imported, like println and kotlins Array, Int, etc types.
What else is imported by default and where is it defined?

Kotlin stdlib has kotlin root package and its subpackages (see the full list with the content).
It seems not to be documented anywhere which of them are imported by default, but a peek into Kotlin Github sources suggests that these packages are imported for JVM target platform:
java.lang.*
kotlin.*
kotlin.annotation.*
kotlin.jvm.*
kotlin.collections.*
kotlin.ranges.*
kotlin.sequences.*
kotlin.text.*
kotlin.io.*
kotlin.coroutines.* (to be added in Kotlin 1.1, not present in 1.0.4)
I've manually tested them, and the list above is true for Kotlin 1.0.4. And these stdlib packages are not imported by default:
kotlin.comparisons.*
kotlin.concurrent.*
kotlin.properties.*
kotlin.reflect.*
kotlin.reflect.jvm.*
kotlin.system.*
As #Magnus noted, the default imports for JS platform are different.

The official documentation for the list of Kotlin's default imports (which is likely to be change with new versions of the language) is here:
https://kotlinlang.org/docs/reference/packages.html#default-imports
As of 2018-02-11 it includes the following:
kotlin.*
kotlin.annotation.*
kotlin.collections.*
kotlin.comparisons.* (since 1.1)
kotlin.io.*
kotlin.ranges.*
kotlin.sequences.*
kotlin.text.*
Additional packages are imported depending on the target platform:
JVM:
java.lang.*
kotlin.jvm.*
JS:
kotlin.js.*

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

Gradle. Custom function in block plugins{}

Can i write in my custom plugin some function like kotlin("jvm")?
plugins {
java
kotlin("jvm") version "1.3.71"
}
I want to write function myplugin("foo") in my custom plugin and then use it like
plugins {
java
kotlin("jvm") version "1.3.71"
custom.plugin
myplugin("foo")
}
How i can do it?
I think that plugins block is some kind of a macro expression. It is parsed and precompiled using a very limited context. Probably, the magic happens somewhere in kotlin-dsl. This is probably the only way to get static accessors and extension functions from plugins to work in Kotlin. I've never seen a mention of this process in Gradle's documentation, but let me explain my thought. Probably, some smart guys from Gradle will correct me.
Let's take a look at some third-party plugin, like Liquibase. It allows you to write something like this in your build.gradle.kts:
liquibase {
activities {
register("name") {
// Configure the activity here
}
}
}
Think about it: in a statically compiled language like Kotlin, in order for this syntaxt to work, there should be an extension named liquibase on a Project type (as it is the type of this object in every build.gradle.kts) available in the classpath of a Gradle's VM that executes the build script.
Indeed, if you click on it, you'll see something like:
fun org.gradle.api.Project.`liquibase`(configure: org.liquibase.gradle.LiquibaseExtension.() -> Unit): Unit =
(this as org.gradle.api.plugins.ExtensionAware).extensions.configure("liquibase", configure)
But take a look at the file where it is defined. In my case it is ~/.gradle/caches/6.3/gradle-kotlin-dsl-accessors/cmljl3ridzazieb8fzn553oa8/cache/src/org/gradle/kotlin/dsl/Accessors39qcxru7gldpadn6lvh8lqs7b.kt. It is definitelly an auto-generated file. A few levels upper in a file tree — at ~/.gradle/caches/6.3/gradle-kotlin-dsl-accessors/ in my case — there are dozens of similar directories. I guess, one by every plugin/version I've ever used with Gradle 6.3. Here is another one for the Detekt plugin:
fun org.gradle.api.Project.`detekt`(configure: io.gitlab.arturbosch.detekt.extensions.DetektExtension.() -> Unit): Unit =
(this as org.gradle.api.plugins.ExtensionAware).extensions.configure("detekt", configure)
So, we have a bunch of .kt files defining all that extensions for different plugins applied to the project. That files are obviously pre-cached and precompiled and their content is available in build.gradle.kts. Indeed, you can find classes directories beside those sources.
The sources are generated based on the content of the applied plugins. It is probably a tricky task that includes some magic, reflection and introspection. Sometimes this magic doesn't work (due too chatic Groovy nature) and then you need to use some crappy DSL from this package.
How are they generated? I see no other way, but to
Parse the build.script.kts with an embedded Kotlin compiler / lexer
Extract all the plugins sections
Compile them, probably against some mocks (remember that Project is not yet available: we're not executing the build.gradle.kts itself yet!)
Resolve the declared plugins from Gradle Plugin repository (with some nuances coming from settngs.gradle.kts)
Introspect plugin's artifacts
Generate the sources
Compile the sources
Add the resulting classes to the script's classpath
And here is the gotcha: there is a very limited context (classpath, classes, methods — call it whatever) available when compiling the plugins block. Actually, no plugins are yet applied! Because, you know, you're parsing the block that applies plugins. Chickens, eggs, and their problems, huh…
So, and we're getting closer to the answer on your question, to provide custom DSL in plugins block, you need to modify that classpath. It's not a classpath of your build.gradle.kts, it's the classpath of the VM that parses build.gradle.kts. Basically, it's Gradle's own classpath — all the classes bundled in a Gradle distribution.
So, probably the only way to provide really custom DSLs in plugins block is to create a custom Gradle distribution.
EDIT:
Indeed, totally forgot to test the buildSrc. I've created a file PluginExtensions.kt in it, with a content
inline val org.gradle.plugin.use.PluginDependenciesSpec.`jawa`: org.gradle.plugin.use.PluginDependencySpec
get() = id("org.gradle.war") // Randomly picked
inline fun org.gradle.plugin.use.PluginDependenciesSpec.`jawa`(): org.gradle.plugin.use.PluginDependencySpec {
return id("org.gradle.cunit") // Randomly picked
}
And it seems to be working:
plugins {
jawa
jawa()
}
However, this is only working when PluginExtensions.kt is in the default package. Whenever I put it into a sub-package, the extensions are not recognized, even with an import:
Magic!
The kotlin function is just a simple extension function wrapping the traditional id method, not hard to define:
fun PluginDependenciesSpec.kotlin(module: String): PluginDependencySpec =
id("org.jetbrains.kotlin.$module")
However, this extension function is part of the standard gradle kotlin DSL API, which means it's available without any plugin. If you want to make a custom function like this available, you would need a plugin. A plugin to load your plugin. Not very practical.
I also tried using the buildSrc module to make an extension function like the above. But it turns out that buildSrc definitions aren't even available from the plugins DSL block, which has a very constrained syntax. That wouldn't have been very practical anyway, you would have needed to make a buildSrc folder for every project in which you have wanted to use the extension.
I'm not sure if this is possible at all. Try asking on https://discuss.gradle.org/.

What do the 'Common', 'JVM', 'JS', and 'JVM' tags indicate in the kotlin docs?

At the top of each class in the docs, for example on the Number class these 4 tags exist at the top and each function has one or more of the tags.
What do they indicate?
These are the target platforms where the corresponding standard library declarations are available. Common means that a declaration may be used in code shared between all platforms in Kotlin Multiplatform projects.
If a declaration is not available on some platform, like readLine (JVM and Native only, but no JS), you won't be able to compile its usage for that specific platform.

No kotlin.Math class in kotlin 1.2 as it is said in the documentation

I have been dealing with kotlin multiplatform alot recently, and I totaly understand the nature of the development. Initially, I had my own expected Math class (in a common module) and I had actual classes in the JS and JVM environment.
Since I like to read the documentations, I found that the Math liblary has been added to the standard liblary since kotlin 1.2. this trouble me as I am using kotlin 1.2.51 and I get an error trying to access the class from kotlin.Math in my common module and any of my platform specific module.
What am I not geting? How do I get access to the kotlin.Math class in my common module?
The Math-class is deprecated and the deprecated-message contains:
Use top-level functions from kotlin.math package instead.
(see also https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.js/-math/index.html)
So somehow the answer of #mTak is right, even though it was not mentioned, that you should use the kotlin.math.*-import instead of your Math-class.
Alternatively, you can also import kotlin.math.max, etc. depending on which function you actually require.
The more I think of it: I don't know whether there ever was a Math-class in the jvm-variant of Kotlin (couldn't find anything regarding it) and so in a multiplatform project the Math-class-access probably should always have failed.
Import it like this: import kotlin.math.*
In the Kotlin standard library math functions are provided as top-level functions in the kotlin.math package.
Therefore you need to import that package and then you'll be able to use functions from it, like sin, sqrt and so on.
import kotlin.math.*
val sqrt2 = sqrt(2.0)
You can also import functions one by one, e.g. import kotlin.math.sqrt or even call them fully qualified val result = kotlin.math.sqrt(2.0)
After a while (I even feel stupid). I found that the kotlin.math library in kotlin common modules was already added. The only difference was, it had no the 'Math.' predecessor as I am normally used to.
So, Math.round(x: Float) was just round(x: Float)
Math.sin(x: Float) was just sin(x: Float)

Can't find ViewModelProviders class, only ViewModelProvider

I am trying to create lifecycle-aware view models. But I can't find ViewModelProviders class in my Android project, only ViewModelProvider. There seems to be no android.arch.lifecycle.ViewModelProviders package for me to import as well. What's happening
You probably have this dependency included in your project:
implementation "android.arch.lifecycle:viewmodel:$lifecycle_version"
That contains ViewModelProvider (and just 4 other classes), but ViewModelProviders is in a different package:
implementation "android.arch.lifecycle:extensions:$lifecycle_version"
Here are the contents of these packages for reference (as of version 1.1.1):
For the record, you can find this out yourself by looking up the docs for the ViewModelProviders class, where it says up top:
added in version 1.1.0
belongs to Maven artifact android.arch.lifecycle:extensions:1.1.1
Also, just for future reference.
ViewModelProviders class is now deprecated.
According to Android Developers Documentation: ViewModelProviders
This class is deprecated. Use the constructors for ViewModelProvider
directly.