Kotlin Docs
Kotlin Docs
Kotlin Docs
Table of Contents
Overview 6
Multiplatform Programming 15
Standard library 43
Tooling 45
Getting Started 46
Basic Syntax 46
Idioms 52
Coding Conventions 57
Basics 75
Basic Types 75
Packages 84
Interfaces 104
Extensions 109
2
Data Classes 115
Generics 118
Delegation 137
Functions 146
Other 180
Ranges 185
Equality 193
Exceptions 203
Annotations 206
Reflection 211
3
Type-Safe Builders 216
Reference 224
Grammar 229
Notation 229
Semicolons 229
Syntax 229
JavaScript 263
Example 277
Native 278
4
Coroutines 317
Supervision 357
Tools 372
Evolution 410
FAQ 430
FAQ 430
5
Overview
Using Kotlin for Server-side Development
Kotlin is a great t for developing server-side applications, allowing to write concise and expressive
code while maintaining full compatibility with existing Java-based technology stacks and a smooth
learning curve:
— Expressiveness: Kotlin's innovative language features, such as its support for type-safe builders
and delegated properties, help build powerful and easy-to-use abstractions.
— Scalability: Kotlin's support for coroutines helps build server-side applications that scale to
massive numbers of clients with modest hardware requirements.
— Interoperability: Kotlin is fully compatible with all Java-based frameworks, which lets you stay
on your familiar technology stack while reaping the bene ts of a more modern language.
— Migration: Kotlin supports gradual, step by step migration of large codebases from Java to
Kotlin. You can start writing new code in Kotlin while keeping older parts of your system in Java.
— Tooling: In addition to great IDE support in general, Kotlin o ers framework-speci c tooling (for
example, for Spring) in the plugin for IntelliJ IDEA Ultimate.
— Learning Curve: For a Java developer, getting started with Kotlin is very easy. The automated
Java to Kotlin converter included in the Kotlin plugin helps with the rst steps. Kotlin Koans o er
a guide through the key features of the language with a series of interactive exercises.
— Vert.x, a framework for building reactive Web applications on the JVM, o ers dedicated support
for Kotlin, including full documentation.
— Ktor is a framework built by JetBrains for creating Web applications in Kotlin, making use of
coroutines for high scalability and o ering an easy-to-use and idiomatic API.
— kotlinx.html is a DSL that can be used to build HTML in a Web application. It serves as an
alternative to traditional templating systems such as JSP and FreeMarker.
— The available options for persistence include direct JDBC access, JPA, as well as using NoSQL
databases through their Java drivers. For JPA, the kotlin-jpa compiler plugin adapts Kotlin-
compiled classes to the requirements of the framework.
6
Deploying Kotlin Server-side Applications
Kotlin applications can be deployed into any host that supports Java Web applications, including
Amazon Web Services, Google Cloud Platform and more.
To deploy Kotlin applications on Heroku, you can follow the o cial Heroku tutorial.
AWS Labs provides a sample project showing the use of Kotlin for writing AWS Lambda functions.
JetBrains Account, the system responsible for the entire license sales and validation process at
JetBrains, is written in 100% Kotlin and has been running in production since 2015 with no major
issues.
Next Steps
— The Creating Web Applications with Http Servlets and Creating a RESTful Web Service with
Spring Boot tutorials show you how you can build and run very small Web applications in Kotlin.
— For a more in-depth introduction to the language, check out the reference documentation on
this site and Kotlin Koans.
7
Using Kotlin for Android Development
Kotlin is a great t for developing Android applications, bringing all of the advantages of a modern
language to the Android platform without introducing any new restrictions:
— Compatibility: Kotlin is fully compatible with JDK 6, ensuring that Kotlin applications can run on
older Android devices with no issues. The Kotlin tooling is fully supported in Android Studio and
compatible with the Android build system.
— Performance: A Kotlin application runs as fast as an equivalent Java one, thanks to very similar
bytecode structure. With Kotlin's support for inline functions, code using lambdas often runs
even faster than the same code written in Java.
— Interoperability: Kotlin is 100% interoperable with Java, allowing to use all existing Android
libraries in a Kotlin application. This includes annotation processing, so databinding and Dagger
work too.
— Footprint: Kotlin has a very compact runtime library, which can be further reduced through the
use of ProGuard. In a real application, the Kotlin runtime adds only a few hundred methods and
less than 100K to the size of the .apk le.
— Compilation Time: Kotlin supports e cient incremental compilation, so while there's some
additional overhead for clean builds, incremental builds are usually as fast or faster than with
Java.
— Learning Curve: For a Java developer, getting started with Kotlin is very easy. The automated
Java to Kotlin converter included in the Kotlin plugin helps with the rst steps. Kotlin Koans o er
a guide through the key features of the language with a series of interactive exercises.
— Pinterest has successfully introduced Kotlin into their application, used by 150M people every
month.
— Basecamp's Android app is 100% Kotlin code, and they report a huge di erence in programmer
happiness and great improvements in work quality and speed.
— Keepsafe's App Lock app has also been converted to 100% Kotlin, leading to a 30% decrease in
source line count and 10% decrease in method count.
— Kotlin Android Extensions is a compiler extension that allows you to get rid of
findViewById() calls in your code and to replace them with synthetic compiler-generated
properties.
8
— Anko is a library providing a set of Kotlin-friendly wrappers around the Android APIs, as well as
a DSL that lets you replace your layout .xml les with Kotlin code.
Next Steps
— Download and install Android Studio 3.0, which includes Kotlin support out of the box.
— Follow the Getting Started with Android and Kotlin tutorial to create your rst Kotlin application.
— For a more in-depth introduction, check out the reference documentation on this site and Kotlin
Koans.
— Another great resource is Kotlin for Android Developers, a book that guides you step by step
through the process of creating a real Android application in Kotlin.
— Check out Google's sample projects written in Kotlin.
9
Kotlin JavaScript Overview
Kotlin provides the ability to target JavaScript. It does so by transpiling Kotlin to JavaScript. The
current implementation targets ECMAScript 5.1 but there are plans to eventually target ECMAScript
2015 as well.
When you choose the JavaScript target, any Kotlin code that is part of the project as well as the
standard library that ships with Kotlin is transpiled to JavaScript. However, this excludes the JDK
and any JVM or Java framework or library used. Any le that is not Kotlin will be ignored during
compilation.
— Interacting with DOM elements. Kotlin provides a series of statically typed interfaces to
interact with the Document Object Model, allowing creation and update of DOM elements.
— Interacting with graphics such as WebGL. You can use Kotlin to create graphical elements
on a web page using WebGL.
— Working with server-side technology. You can use Kotlin to interact with server-side
JavaScript such as Node.js
Kotlin can be used together with existing third-party libraries and frameworks, such as jQuery or
React. To access third-party frameworks with a strongly-typed API, you can convert TypeScript
de nitions from the De nitely Typed type de nitions repository to Kotlin using the ts2kt tool.
Alternatively, you can use the dynamic type to access any framework without strong typing.
JetBrains develops and maintains several tools speci cally for the React community: React bindings
as well as Create React Kotlin App. The latter helps you start building React apps with Kotlin with no
build con guration.
Kotlin is compatible with CommonJS, AMD and UMD, making interaction with di erent module
systems straightforward.
10
To nd out how to start using Kotlin for JavaScript, please refer to the tutorials.
11
Kotlin/Native for Native
Kotlin/Native is a technology for compiling Kotlin code to native binaries, which can run without a
virtual machine. It is an LLVM based backend for the Kotlin compiler and native implementation of
the Kotlin standard library.
Why Kotlin/Native?
Kotlin/Native is primarily designed to allow compilation for platforms where virtual machines are
not desirable or possible, for example, embedded devices or iOS. It solves the situations when a
developer needs to produce a self-contained program that does not require an additional runtime
or virtual machine.
Target Platforms
Kotlin/Native supports the following platforms:
Interoperability
Kotlin/Native supports two-way interoperability with the Native world. On the one hand, the
compiler creates:
On the other hand, Kotlin/Native supports interoperability to use existing libraries directly from
Kotlin/Native:
It is easy to include a compiled Kotlin code into existing projects written in C, C++, Swift, Objective-
C, and other languages. It is also easy to use existing native code, static or dynamic C libraries,
Swift/Objective-C frameworks, graphical engines, and anything else directly from Kotlin/Native.
Kotlin/Native libraries help to share Kotlin code between projects. POSIX, gzip, OpenGL, Metal,
Foundation, and many other popular libraries and Apple frameworks are pre-imported and
included as Kotlin/Native libraries into the compiler package.
12
Sharing Code between Platforms
Multiplatform projects are supported between di erent Kotlin and Kotlin/Native targets. This is the
way to share common Kotlin code between many platforms, including Android, iOS, server-side,
JVM, client-side, JavaScript, CSS, and native.
Multiplatform libraries provide the necessary APIs for the common Kotlin code and help to develop
shared parts of a project in Kotlin code once and share it with all of the target platforms.
How to Start
— C interop
— Swift/Objective-C interop
Recommended tutorials:
Example Projects
13
Coroutines for asynchronous programming and more
Asynchronous or non-blocking programming is the new reality. Whether we're creating server-side,
desktop or mobile applications, it's important that we provide an experience that is not only uid
from the user's perspective, but scalable when needed.
There are many approaches to this problem, and in Kotlin we take a very exible one by providing
Coroutine support at the language level and delegating most of the functionality to libraries, much
in line with Kotlin's philosophy.
As a bonus, coroutines not only open the doors to asynchronous programming, but also provide a
wealth of other possibilities such as concurrency, actors, etc.
How to Start
— Coroutines Guide
— Basics
— Channels
— Coroutine Context and Dispatchers
— Shared Mutable State and Concurrency
Recommended tutorials:
Example Projects
14
Multiplatform Programming
Multiplatform projects are an experimental feature in Kotlin 1.2 and 1.3. All of the
language and tooling features described in this document are subject to change in future
Kotlin versions.
Working on all platforms is an explicit goal for Kotlin, but we see it as a premise to a much more
important goal: sharing code between platforms. With support for JVM, Android, JavaScript, iOS,
Linux, Windows, Mac and even embedded systems like STM32, Kotlin can handle any and all
components of a modern application. And this brings the invaluable bene t of reuse for code and
expertise, saving the e ort for tasks more challenging than implementing everything twice or
multiple times.
How it works
Overall, multiplatform is not about compiling all code for all platforms. This model has its obvious
limitations, and we understand that modern applications need access to unique features of the
platforms they are running on. Kotlin doesn't limit you to the common subset of all APIs in the
world. Every component can share as much code as needed with others but can access platform
APIs at any time through the expect/actual mechanism provided by the language.
Here's an example of code sharing and interaction between the common and platform logic in a
minimalistic logging framework. The common code would look like this:
On the JVM, one could provide an implementation that writes the log to the standard output:
15
In the JavaScript world, a completely di erent set of APIs is availiable, so one could instead
implement logging to the console:
In 1.3 we reworked the entire multiplatform model. The new DSL we have for describing
multiplatform Gradle projects is much more exible, and we'll keep working on it to make project
con guration straightforward.
Multiplatform Libraries
Common code can rely on a set of libraries that cover everyday tasks such as HTTP, serialization,
and managing coroutines. Also, an extensive standard library is available on all platforms.
You can always write your own library providing a common API and implementing it di erently on
every platform.
Use cases
Android — iOS
Sharing code between mobile platforms is one of the major Kotlin Multiplatform use cases, and it is
now possible to build mobile applications with parts of the code, such as business logic,
connectivity, and more, shared between Android and iOS.
Client — Server
Another scenario when code sharing may bring bene ts is a connected application where the logic
may be reused on both the server and the client side running in the browser. This is covered by
Kotlin Multiplatform as well.
The Ktor framework is suitable for building asynchronous servers and clients in connected systems.
How to start
16
— Platform-Speci c Declarations
Recommended tutorials:
Example Projects
— KotlinConf app
— KotlinConf Spinner app
17
What's New in Kotlin 1.1
Table of Contents
— Coroutines
— Other language features
— Standard library
— JVM backend
— JavaScript backend
JavaScript
Starting with Kotlin 1.1, the JavaScript target is no longer considered experimental. All language
features are supported, and there are many new tools for integration with the front-end
development environment. See below for a more detailed list of changes.
Coroutines (experimental)
The key new feature in Kotlin 1.1 is coroutines, bringing the support of async / await , yield and
similar programming patterns. The key feature of Kotlin's design is that the implementation of
coroutine execution is part of the libraries, not the language, so you aren't bound to any speci c
programming paradigm or concurrency library.
A coroutine is e ectively a light-weight thread that can be suspended and resumed later.
Coroutines are supported through suspending functions: a call to such a function can potentially
suspend a coroutine, and to start a new coroutine we usually use an anonymous suspending
functions (i.e. suspending lambdas).
Here, async { ... } starts a coroutine and, when we use await() , the execution of the
coroutine is suspended while the operation being awaited is executed, and is resumed (possibly on
a di erent thread) when the operation being awaited completes.
18
The standard library uses coroutines to support lazily generated sequences with yield and
yieldAll functions. In such a sequence, the block of code that returns sequence elements is
suspended after each element has been retrieved, and resumed when the next element is
requested. Here's an example:
Run the code above to see the result. Feel free to edit it and run again!
For more information, please refer to the coroutine documentation and tutorial.
Note that coroutines are currently considered an experimental feature, meaning that the Kotlin
team is not committing to supporting the backwards compatibility of this feature after the nal 1.1
release.
Type aliases
A type alias allows you to de ne an alternative name for an existing type. This is most useful for
generic types such as collections, as well as for function types. Here is an example:
// Note that the type names (initial and the type alias) are interchangeable:
fun checkLaLaLandIsTheBestMovie(oscarWinners: Map<String, String>) =
oscarWinners["Best picture"] == "La La Land"
You can now use the :: operator to get a member reference pointing to a method or property of
a speci c object instance. Previously this could only be expressed with a lambda. Here's an
example:
19
Sealed and data classes
Kotlin 1.1 removes some of the restrictions on sealed and data classes that were present in Kotlin
1.0. Now you can de ne subclasses of a top-level sealed class on the top level in the same le, and
not just as nested classes of the sealed class. Data classes can now extend other classes. This can
be used to de ne a hierarchy of expression classes nicely and cleanly:
Read the documentation or sealed class and data class KEEPs for more detail.
Destructuring in lambdas
You can now use the destructuring declaration syntax to unpack the arguments passed to a
lambda. Here's an example:
For a lambda with multiple parameters, you can use the _ character to replace the names of the
parameters you don't use:
20
Just as in Java 8, Kotlin now allows to use underscores in numeric literals to separate groups of
digits:
For properties with the getter de ned as an expression body, the property type can now be
omitted:
You can now mark property accessors with the inline modi er if the properties don't have a
backing eld. Such accessors are compiled in the same way as inline functions.
You can also mark the entire property as inline - then the modi er is applied to both accessors.
You can now use the delegated property syntax with local variables. One possible use is de ning a
lazily evaluated local variable:
21
For delegated properties, it is now possible to intercept delegate to property binding using the
provideDelegate operator. For example, if we want to check the property name before binding,
we can write something like this:
class MyUI {
val image by bindResource(ResourceID.image_id)
val text by bindResource(ResourceID.text_id)
}
The provideDelegate method will be called for each property during the creation of a MyUI
instance, and it can perform the necessary validation right away.
The @DslMarker annotation allows to restrict the use of receivers from outer scopes in a DSL
context. Consider the canonical HTML builder example:
table {
tr {
td { + "Text" }
}
}
In Kotlin 1.0, code in the lambda passed to td has access to three implicit receivers: the one
passed to table , to tr and to td . This allows you to call methods that make no sense in the
context - for example to call tr inside td and thus to put a <tr> tag in a <td> .
22
In Kotlin 1.1, you can restrict that, so that only methods de ned on the implicit receiver of td will
be available inside the lambda passed to td . You do that by de ning your annotation marked with
the @DslMarker meta-annotation and applying it to the base class of the tag classes.
rem operator
The mod operator is now deprecated, and rem is used instead. See this issue for motivation.
Standard library
There is a bunch of new extensions on the String class to convert it to a number without throwing
an exception on invalid number: String.toIntOrNull(): Int? ,
String.toDoubleOrNull(): Double? etc.
onEach()
onEach is a small, but useful extension function for collections and sequences, which allows to
perform some action, possibly with side-e ects, on each element of the collection/sequence in a
chain of operations. On iterables it behaves like forEach but also returns the iterable instance
further. And on sequences it returns a wrapping sequence, which applies the given action lazily as
the elements are being iterated.
inputDir.walk()
.filter { it.isFile && it.name.endsWith(".txt") }
.onEach { println("Moving $it to $outputDir") }
.forEach { moveFile(it, File(outputDir, it.toRelativeString(inputDir))) }
also is like apply : it takes the receiver, does some action on it, and returns that receiver. The
di erence is that in the block inside apply the receiver is available as this , while in the block
inside also it's available as it (and you can give it another name if you want). This comes handy
when you do not want to shadow this from the outer scope:
23
fun Block.copy() = Block().also {
it.content = this.content
}
takeIf is like filter for a single value. It checks whether the receiver meets the predicate, and
returns the receiver, if it does or null if it doesn't. Combined with an elvis-operator and early
returns it allows to write constructs like:
takeUnless is the same as takeIf , but it takes the inverted predicate. It returns the receiver
when it doesn't meet the predicate and null otherwise. So one of the examples above could be
rewritten with takeUnless as following:
It is also convenient to use when you have a callable reference instead of the lambda:
groupingBy()
This API can be used to group a collection by key and fold each group simultaneously. For example,
it can be used to count the number of words starting with each letter:
Map.minus(key)
The operator plus provides a way to add key-value pair(s) to a read-only map producing a new
map, however there was not a simple way to do the opposite: to remove a key from the map you
have to resort to less straightforward ways to like Map.filter() or Map.filterKeys() . Now
the operator minus lls this gap. There are 4 overloads available: for removing a single key, a
collection of keys, a sequence of keys and an array of keys.
24
minOf() and maxOf()
These functions can be used to nd the lowest and greatest of two or three given values, where
values are primitive numbers or Comparable objects. There is also an overload of each function
that take an additional Comparator instance, if you want to compare objects that are not
comparable themselves.
Similar to the Array constructor, there are now functions that create List and MutableList
instances and initialize each element by calling a lambda:
Map.getValue()
This extension on Map returns an existing value corresponding to the given key or throws an
exception, mentioning which key was not found. If the map was produced with withDefault , this
function will return the default value instead of throwing an exception.
Abstract collections
These abstract classes can be used as base classes when implementing Kotlin collection classes. For
implementing read-only collections there are AbstractCollection , AbstractList ,
AbstractSet and AbstractMap , and for mutable collections there are
AbstractMutableCollection , AbstractMutableList , AbstractMutableSet and
AbstractMutableMap . On JVM these abstract mutable collections inherit most of their
functionality from JDK's abstract collections.
25
The standard library now provides a set of functions for element-by-element operations on arrays:
comparison ( contentEquals and contentDeepEquals ), hash code calculation
( contentHashCode and contentDeepHashCode ), and conversion to a string
( contentToString and contentDeepToString ). They're supported both for the JVM (where
they act as aliases for the corresponding functions in java.util.Arrays ) and for JS (where the
implementation is provided in the Kotlin standard library).
JVM Backend
Kotlin has now the option of generating Java 8 bytecode ( -jvm-target 1.8 command line
option or the corresponding options in Ant/Maven/Gradle). For now this doesn't change the
semantics of the bytecode (in particular, default methods in interfaces and lambdas are generated
exactly as in Kotlin 1.0), but we plan to make further use of this later.
There are now separate versions of the standard library supporting the new JDK APIs added in Java
7 and 8. If you need access to the new APIs, use kotlin-stdlib-jre7 and kotlin-stdlib-
jre8 maven artifacts instead of the standard kotlin-stdlib . These artifacts are tiny extensions
on top of kotlin-stdlib and they bring it to your project as a transitive dependency.
Kotlin now supports storing parameter names in the bytecode. This can be enabled using the -
java-parameters command line option.
Constant inlining
The compiler now inlines values of const val properties into the locations where they are used.
The box classes used for capturing mutable closure variables in lambdas no longer have volatile
elds. This change improves performance, but can lead to new race conditions in some rare usage
scenarios. If you're a ected by this, you need to provide your own synchronization for accessing
the variables.
javax.script support
26
Kotlin now integrates with the javax.script API (JSR-223). The API allows to evaluate snippets of code
at runtime:
kotlin.re ect.full
To prepare for Java 9 support, the extension functions and properties in the kotlin-
reflect.jar library have been moved to the package kotlin.reflect.full . The names in
the old package ( kotlin.reflect ) are deprecated and will be removed in Kotlin 1.2. Note that
the core re ection interfaces (such as KClass ) are part of the Kotlin standard library, not
kotlin-reflect , and are not a ected by the move.
JavaScript Backend
A much larger part of the Kotlin standard library can now be used from code compiled to
JavaScript. In particular, key classes such as collections ( ArrayList , HashMap etc.), exceptions
( IllegalArgumentException etc.) and a few others ( StringBuilder , Comparator ) are now
de ned under the kotlin package. On the JVM, the names are type aliases for the corresponding
JDK classes, and on the JS, the classes are implemented in the Kotlin standard library.
JavaScript backend now generates more statically checkable code, which is friendlier to JS code
processing tools, like mini ers, optimisers, linters, etc.
If you need to access a class implemented in JavaScript from Kotlin in a typesafe way, you can write
a Kotlin declaration using the external modi er. (In Kotlin 1.0, the @native annotation was
used instead.) Unlike the JVM target, the JS one permits to use external modi er with classes and
properties. For example, here's how you can declare the DOM Node class:
// etc
}
27
Improved import handling
You can now describe declarations which should be imported from JavaScript modules more
precisely. If you add the @JsModule("<module-name>") annotation on an external declaration
it will be properly imported to a module system (either CommonJS or AMD) during the compilation.
For example, with CommonJS the declaration will be imported via require(...) function.
Additionally, if you want to import a declaration either as a module or as a global JavaScript object,
you can use the @JsNonModule annotation.
For example, here's how you can import JQuery into a Kotlin module:
@JsModule("jquery")
@JsNonModule
@JsName("$")
external fun jquery(selector: String): JQuery
In this case, JQuery will be imported as a module named jquery . Alternatively, it can be used as a
$-object, depending on what module system Kotlin compiler is con gured to use.
28
What's New in Kotlin 1.2
Table of Contents
— Multiplatform projects
— Other language features
— Standard library
— JVM backend
— JavaScript backend
— A common module contains code that is not speci c to any platform, as well as declarations
without implementation of platform-dependent APIs.
— A platform module contains implementations of platform-dependent declarations in the
common module for a speci c platform, as well as other platform-dependent code.
— A regular module targets a speci c platform and can either be a dependency of platform
modules or depend on platform modules.
When you compile a multiplatform project for a speci c platform, the code for both the common
and platform-speci c parts is generated.
A key feature of the multiplatform project support is the possibility to express dependencies of
common code on platform-speci c parts through expected and actual declarations. An expected
declaration speci es an API (class, interface, annotation, top-level declaration etc.). An actual
declaration is either a platform-dependent implementation of the API or a typealias referring to an
existing implementation of the API in an external library. Here's an example:
In common code:
fun greet() {
// usage of the expected API:
val greeting = hello("multi-platform world")
println(greeting)
}
29
actual fun hello(world: String): String =
"Hello, $world, on the JVM platform!"
See the documentation for details and steps to build a multiplatform project.
Starting with Kotlin 1.2, array arguments for annotations can be passed with the new array literal
syntax instead of the arrayOf function:
The lateinit modi er can now be used on top-level properties and local variables. The latter
can be used, for example, when a lambda passed as a constructor argument to one object refers to
another object which has to be de ned later:
You can now check whether a lateinit var has been initialized using isInitialized on the
property reference:
30
Inline functions with default functional parameters
Inline functions are now allowed to have default values for their inlined functional parameters:
The Kotlin compiler can now use information from type casts in type inference. If you’re calling a
generic method that returns a type parameter T and casting the return value to a speci c type
Foo , the compiler now understands that T for this call needs to be bound to the type Foo .
This is particularly important for Android developers, since the compiler can now correctly analyze
generic findViewById calls in Android API level 26:
When a variable is assigned from a safe call expression and checked for null, the smart cast is now
applied to the safe call receiver as well:
Also, smart casts in a lambda are now allowed for local variables that are only modi ed before the
lambda:
run {
if (x != null) {
println(x.length) // x is smart cast to String
}
}
A bound callable reference to a member of this can now be written without explicit receiver,
::foo instead of this::foo . This also makes callable references more convenient to use in
lambdas where you refer to a member of the outer receiver.
31
Breaking change: sound smart casts after try blocks
Earlier, Kotlin used assignments made inside a try block for smart casts after the block, which
could break type- and null-safety and lead to runtime failures. This release xes this issue, making
the smart casts more strict, but breaking some code that relied on such smart casts.
To switch to the old smart casts behavior, pass the fallback ag -Xlegacy-smart-cast-after-
try as the compiler argument. It will become deprecated in Kotlin 1.3.
When a data class derived from a type that already had the copy function with the same
signature, the copy implementation generated for the data class used the defaults from the
supertype, leading to counter-intuitive behavior, or failed at runtime if there were no default
parameters in the supertype.
Inheritance that leads to a copy con ict has become deprecated with a warning in Kotlin 1.2 and
will be an error in Kotlin 1.3.
Inside enum entries, de ning a nested type that is not an inner class has been deprecated due
to issues in the initialization logic. This causes a warning in Kotlin 1.2 and will become an error in
Kotlin 1.3.
For consistency with array literals in annotations, passing a single item for a vararg parameter in
the named form ( foo(items = i) ) has been deprecated. Please use the spread operator with
the corresponding array factory functions:
foo(items = *intArrayOf(1))
There is an optimization that removes redundant arrays creation in such cases, which prevents
performance degradation. The single-argument form produces warnings in Kotlin 1.2 and is to be
dropped in Kotlin 1.3.
Inner classes of generic types that inherit from Throwable could violate type-safety in a throw-
catch scenario and thus have been deprecated, with a warning in Kotlin 1.2 and an error in Kotlin
1.3.
32
Mutating the backing eld of a read-only property by assigning field = ... in the custom getter
has been deprecated, with a warning in Kotlin 1.2 and an error in Kotlin 1.3.
Standard Library
The Kotlin standard library is now fully compatible with the Java 9 module system, which forbids
split packages (multiple jar les declaring classes in the same package). In order to support that,
new artifacts kotlin-stdlib-jdk7 and kotlin-stdlib-jdk8 are introduced, which replace
the old kotlin-stdlib-jre7 and kotlin-stdlib-jre8 .
The declarations in the new artifacts are visible under the same package names from the Kotlin
point of view, but have di erent package names for Java. Therefore, switching to the new artifacts
will not require any changes to your source code.
Another change made to ensure compatibility with the new module system is removing the
deprecated declarations in the kotlin.reflect package from the kotlin-reflect library. If
you were using them, you need to switch to using the declarations in the kotlin.reflect.full
package, which is supported since Kotlin 1.1.
New extensions for Iterable<T> , Sequence<T> , and CharSequence cover such use cases as
bu ering or batch processing ( chunked ), sliding window and computing sliding average
( windowed ) , and processing pairs of subsequent items ( zipWithNext ):
A set of extension functions was added for manipulating lists: fill , replaceAll and shuffle
for MutableList , and shuffled for read-only List :
items.shuffle()
println("Shuffled items: $items")
items.replaceAll { it * 2 }
println("Items doubled: $items")
items.fill(5)
println("Items filled with 5: $items")
33
Math operations in kotlin-stdlib
Satisfying the longstanding request, Kotlin 1.2 adds the kotlin.math API for math operations
that is common for JVM and JS and contains the following:
— Constants: PI and E ;
— Trigonometric: cos , sin , tan and inverse of them: acos , asin , atan , atan2 ;
— Hyperbolic: cosh , sinh , tanh and their inverse: acosh , asinh , atanh
— Rounding:
— ceil , floor , truncate , round (half to even) functions;
— Binary representation:
— ulp extension property;
The same set of functions (but without constants) is also available for Float arguments.
Kotlin 1.2 introduces a set of functions for operating with BigInteger and BigDecimal and
creating them from other numeric types. These are:
34
New functions were added for converting Double and Float to and from their bit
representations:
— toBits and toRawBits returning Long for Double and Int for Float ;
— Double.fromBits and Float.fromBits for creating oating point numbers from the bit
representation.
The kotlin.text.Regex class has become Serializable and can now be used in serializable
hierarchies.
JVM Backend
Ever since version 1.0, Kotlin supported expressions with complex control ow, such as try-catch
expressions and inline function calls. Such code is valid according to the Java Virtual Machine
speci cation. Unfortunately, some bytecode processing tools do not handle such code quite well
when such expressions are present in the arguments of constructor calls.
To mitigate this problem for the users of such bytecode processing tools, we’ve added a command-
line option ( -Xnormalize-constructor-calls=MODE ) that tells the compiler to generate more
Java-like bytecode for such constructs. Here MODE is one of:
— disable (default) – generate bytecode in the same way as in Kotlin 1.0 and 1.1;
— enable – generate Java-like bytecode for constructor calls. This can change the order in which
the classes are loaded and initialized;
— preserve-class-initialization – generate Java-like bytecode for constructor calls,
ensuring that the class initialization order is preserved. This can a ect overall performance of
your application; use it only if you have some complex state shared between multiple classes
and updated on class initialization.
The “manual” workaround is to store the values of sub-expressions with control ow in variables,
instead of evaluating them directly inside the call arguments. It’s similar to -Xnormalize-
constructor-calls=enable .
35
Before Kotlin 1.2, interface members overriding Java-default methods while targeting JVM 1.6
produced a warning on super calls: Super calls to Java default methods are
deprecated in JVM target 1.6. Recompile with '-jvm-target 1.8' . In Kotlin 1.2,
there's an error instead, thus requiring any such code to be compiled with JVM target 1.8.
Inline extension functions that were called on a null value of a platform type did not check the
receiver for null and would thus allow null to escape into the other code. Kotlin 1.2 forces this
check at the call sites, throwing an exception if the receiver is null.
JavaScript Backend
The JS typed arrays support that translates Kotlin primitive arrays, such as IntArray ,
DoubleArray , into JavaScript typed arrays, that was previously an opt-in feature, has been
enabled by default.
Tools
Warnings as errors
The compiler now provides an option to treat all warnings as errors. Use -Werror on the
command line, or the following Gradle snippet:
compileKotlin {
kotlinOptions.allWarningsAsErrors = true
}
36
What's New in Kotlin 1.3
Coroutines release
After some long and extensive battle testing, coroutines are now released! It means that from
Kotlin 1.3 the language support and the API are fully stable. Check out the new coroutines overview
page.
Kotlin 1.3 introduces callable references on suspend-functions and support of Coroutines in the
Re ection API.
Kotlin/Native
Kotlin 1.3 continues to improve and polish the Native target. See the Kotlin/Native overview for
details.
Multiplatform Projects
In 1.3, we've completely reworked the model of multiplatform projects in order to improve
expressiveness and exibility, and to make sharing common code easier. Also, Kotlin/Native is now
supported as one of the targets!
— In the old model, common and platform-speci c code needed to be placed in separate modules,
linked by expectedBy dependencies. Now, common and platform-speci c code is placed in
di erent source roots of the same module, making projects easier to con gure.
— There is now a large number of preset platform con gurations for di erent supported
platforms.
— The dependencies con guration has been changed; dependencies are now speci ed separately
for each source root.
— Source sets can now be shared between an arbitrary subset of platforms (for example, in a
module that targets JS, Android and iOS, you can have a source set that is shared only between
Android and iOS).
— Publishing multiplatform libraries is now supported.
Contracts
The Kotlin compiler does extensive static analysis to provide warnings and reduce boilerplate. One
of the most notable features is smartcasts — with the ability to perform a cast automatically based
on the performed type checks:
37
However, as soon as these checks are extracted in a separate function, all the smartcasts
immediately disappear:
To improve the behavior in such cases, Kotlin 1.3 introduces experimental mechanism called
contracts.
Contracts allow a function to explicitly describe its behavior in a way which is understood by the
compiler. Currently, two wide classes of cases are supported:
— Improving smartcasts analysis by declaring the relation between a function's call outcome and
the passed arguments values:
fun foo() {
val x: Int
synchronize(lock) {
x = 42 // Compiler knows that lambda passed to 'synchronize' is called
// exactly once, so no reassignment is reported
}
println(x) // Compiler knows that lambda will be definitely called, performing
// initialization, so 'x' is considered to be initialized here
}
Contracts in stdlib
stdlib already makes use of contracts, which leads to improvements in the analyses described
above. This part of contracts is stable, meaning that you can bene t from the improved analysis
right now without any additional opt-ins:
38
fun bar(x: String?) {
if (!x.isNullOrEmpty()) {
println("length of '$x' is ${x.length}") // Yay, smartcasted to not-null!
}
}
Custom Contracts
It is possible to declare contracts for your own functions, but this feature is experimental, as the
current syntax is in a state of early prototype and will most probably be changed. Also, please note,
that currently the Kotlin compiler does not verify contracts, so it's a programmer's responsibility to
write correct and sound contracts.
Custom contracts are introduced by the call to contract stdlib function, which provides DSL
scope:
See the details on the syntax as well as the compatibility notice in the KEEP.
fun Request.getBody() =
when (val response = executeRequest()) {
is Success -> response.body
is HttpError -> throw HttpException(response.status)
}
While it was already possible to extract this variable just before when , val in when has its scope
properly restricted to the body of when , and so preventing namespace pollution. See the full
documentation on when here.
39
interface Foo {
companion object {
@JvmField
val answer: Int = 42
@JvmStatic
fun sayHello() {
println("Hello, world!")
}
}
}
interface Foo {
public static int answer = 42;
public static void sayHello() {
// ...
}
}
companion object {
fun foo(): Int = 42
val bar: Int = 42
}
}
Parameterless main
By convention, the entry point of a Kotlin program is a function with a signature like main(args:
Array<String>) , where args represent the command-line arguments passed to the program.
However, not every application supports command-line arguments, so this parameter often ends
up not being used.
Kotlin 1.3 introduced a simpler form of main which takes no parameters. Now “Hello, World” in
Kotlin is 19 characters shorter!
fun main() {
println("Hello, world!")
}
40
In Kotlin, functional types are represented as generic classes taking a di erent number of
parameters: Function0<R> , Function1<P0, R> , Function2<P0, P1, R> , … This approach
has a problem in that this list is nite, and it currently ends with Function22 .
Kotlin 1.3 relaxes this limitation and adds support for functions with bigger arity:
fun trueEnterpriseComesToKotlin(block: (Any, Any, ... /* 42 more */, Any) -> Any) {
block(Any(), Any(), ..., Any())
}
Progressive mode
Kotlin cares a lot about stability and backward compatibility of code: Kotlin compatibility policy says
that "breaking changes" (e.g., a change which makes the code that used to compile ne, not
compile anymore) can be introduced only in the major releases (1.2, 1.3, etc.).
We believe that a lot of users could use a much faster cycle, where critical compiler bug xes arrive
immediately, making the code more safe and correct. So, Kotlin 1.3 introduces progressive compiler
mode, which can be enabled by passing the argument -progressive to the compiler.
In progressive mode, some xes in language semantics can arrive immediately. All these xes have
two important properties:
— they preserve backward-compatibility of source code with older compilers, meaning that all the
code which is compilable by the progressive compiler will be compiled ne by non-progressive
one.
— they only make code safer in some sense — e.g., some unsound smartcast can be forbidden,
behavior of the generated code may be changed to be more predictable/stable, and so on.
Enabling the progressive mode can require you to rewrite some of your code, but it shouldn't be
too much — all the xes which are enabled under progressive are carefully handpicked, reviewed,
and provided with tooling migration assistance. We expect that the progressive mode will be a nice
choice for any actively maintained codebases which are updated to the latest language versions
quickly.
Inline classes
Inline classes are available only since Kotlin 1.3 and currently are experimental. See details
in the reference.
Kotlin 1.3 introduces a new kind of declaration — inline class . Inline classes can be viewed as
a restricted version of the usual classes, in particular, inline classes must have exactly one property:
41
The Kotlin compiler will use this restriction to aggressively optimize runtime representation of
inline classes and substitute their instances with the value of the underlying property where
possible removing constructor calls, GC pressure, and enabling other optimizations:
fun main() {
// In the next line no constructor call happens, and
// at the runtime 'name' contains just string "Kotlin"
val name = Name("Kotlin")
println(name.s)
}
Unsigned integers
Unsigned integers are available only since Kotlin 1.3 and currently are experimental. See
details in the reference.
Most of the functionality of signed types are supported for unsigned counterparts too:
// You can convert signed types to unsigned and vice versa via stdlib extensions:
val int = uint.toInt()
val byte = ubyte.toByte()
val ulong2 = byte.toULong()
@JvmDefault
@JvmDefault is only available since Kotlin 1.3 and currently is experimental. See details in
the reference page.
42
Kotlin targets a wide range of the Java versions, including Java 6 and Java 7, where default methods
in the interfaces are not allowed. For your convenience, the Kotlin compiler works around that
limitation, but this workaround isn't compatible with the default methods, introduced in Java 8.
This could be an issue for Java-interoperability, so Kotlin 1.3 introduces the @JvmDefault
annotation. Methods, annotated with this annotation will be generated as default methods for
JVM:
interface Foo {
// Will be generated as 'default' method
@JvmDefault
fun foo(): Int = 42
}
Warning! Annotating your API with @JvmDefault has serious implications on binary
compatibility. Make sure to carefully read the reference page before using @JvmDefault
in production.
Standard library
Multiplatform Random
Prior to Kotlin 1.3, there was no uniform way to generate random numbers on all platforms — we
had to resort to platform speci c solutions, like java.util.Random on JVM. This release xes
this issue by introducing the class kotlin.random.Random , which is available on all platforms:
isNullOrEmpty/orEmpty extensions
isNullOrEmpty and orEmpty extensions for some types are already present in stdlib . The rst
one returns true if the receiver is null or empty, and the second one falls back to an empty
instance if the receiver is null . Kotlin 1.3 provides similar extensions on collections, maps, and
arrays of objects.
43
val sourceArr = arrayOf("k", "o", "t", "l", "i", "n")
val targetArr = sourceArr.copyInto(arrayOfNulls<String>(6), 3, startIndex = 3, endIndex =
6)
println(targetArr.contentToString())
associateWith
It is quite a common situation to have a list of keys and want to build a map by associating each of
these keys with some value. It was possible to do it before with the associate { it to
getValue(it) } function, but now we’re introducing a more e cient and easy to explore
alternative: keys.associateWith { getValue(it) } .
printAllUppercase(listOf("foo", "Bar"))
printAllUppercase(listOf("FOO", "BAR"))
Char sequences and strings in addition have an ifBlank extension that does the same thing as
ifEmpty , but checks for a string being all whitespace instead of empty.
Smaller changes
— Boolean type now has companion.
44
— SIZE_BYTES and SIZE_BITS constants in primitive type companions.
Tooling
kotlinx.serialization
kotlinx.serialization is a library which provides multiplatform support for (de)serializing objects in
Kotlin. Previously, it was a separate project, but since Kotlin 1.3, it ships with the Kotlin compiler
distribution on par with the other compiler plugins. The main di erence is that you don't need to
manually watch out for the Serialization IDE Plugin being compatible with the Kotlin IDE Plugin
version you're using: now the Kotlin IDE Plugin already includes serialization!
Please, note, that even though kotlinx.serialization now ships with the Kotlin Compiler
distribution, it is still considered to be an experimental feature.
Scripting update
Kotlin 1.3 continues to evolve and improve scripting API, introducing some experimental support
for scripts customization, such as adding external properties, providing static or dynamic
dependencies, and so on.
Scratches support
Kotlin 1.3 introduces support for runnable Kotlin scratch les. Scratch le is a kotlin script le with a
.kts extension which you can run and get evaluation results directly in the editor.
45
Getting Started
Basic Syntax
De ning packages
Package speci cation should be at the top of the source le:
package my.demo
import java.util.*
// ...
It is not required to match directories and packages: source les can be placed arbitrarily in the le
system.
See Packages.
De ning functions
Function having two Int parameters with Int return type:
See Functions.
De ning variables
46
Read-only local variables are de ned using the keyword val . They can be assigned a value only
once.
Top-level variables:
val PI = 3.14
var x = 0
fun incrementX() {
x += 1
}
Comments
Just like Java and JavaScript, Kotlin supports end-of-line and block comments.
See Documenting Kotlin Code for information on the documentation comment syntax.
a = 2
// arbitrary expression in template:
val s2 = "${s1.replace("is", "was")}, but now is $a"
47
fun maxOf(a: Int, b: Int): Int {
if (a > b) {
return a
} else {
return b
}
}
Using if as an expression:
See if-expressions.
or
// ...
if (x == null) {
println("Wrong number format in arg1: '$arg1'")
return
}
if (y == null) {
println("Wrong number format in arg2: '$arg2'")
return
}
See Null-safety.
48
Using type checks and automatic casts
The is operator checks if an expression is an instance of a type. If an immutable local variable or
property is checked for a speci c type, there's no need to cast it explicitly:
or
or even
return null
}
or
49
val items = listOf("apple", "banana", "kiwifruit")
var index = 0
while (index < items.size) {
println("item at $index is ${items[index]}")
index++
}
Using ranges
Check if a number is within a range using in operator:
val x = 10
val y = 9
if (x in 1..y+1) {
println("fits in range")
}
for (x in 1..5) {
print(x)
}
or over a progression:
50
for (x in 1..10 step 2) {
print(x)
}
println()
for (x in 9 downTo 0 step 3) {
print(x)
}
See Ranges.
Using collections
Iterating over a collection:
when {
"orange" in items -> println("juicy")
"apple" in items -> println("apple is fine too")
}
51
Idioms
A collection of random and frequently used idioms in Kotlin. If you have a favorite idiom,
contribute it by sending a pull request.
— equals()
— hashCode()
— toString()
— copy()
Filtering a list
String Interpolation
println("Name $name")
Instance Checks
when (x) {
is Foo -> ...
is Bar -> ...
else -> ...
}
52
k , v can be called anything.
Using ranges
Read-only list
Read-only map
Accessing a map
println(map["key"])
map["key"] = value
Lazy property
Extension Functions
Creating a singleton
object Resource {
val name = "Name"
}
println(files?.size)
53
val files = File("Test").listFiles()
println(files?.size ?: "empty")
value?.let {
... // execute this block if not null
}
'try/catch' expression
fun test() {
val result = try {
count()
} catch (e: ArithmeticException) {
throw IllegalStateException(e)
}
'if' expression
54
fun foo(param: Int) {
val result = if (param == 1) {
"one"
} else if (param == 2) {
"two"
} else {
"three"
}
}
Single-expression functions
fun theAnswer() = 42
This is equivalent to
This can be e ectively combined with other idioms, leading to shorter code. E.g. with the when-
expression:
class Turtle {
fun penDown()
fun penUp()
fun turn(degrees: Double)
fun forward(pixels: Double)
}
55
Java 7's try with resources
Convenient form for a generic function that requires the generic type information
56
Coding Conventions
This page contains the current coding style for the Kotlin language.
To con gure the IntelliJ formatter according to this style guide, please install Kotlin plugin version
1.2.20 or newer, go to Settings | Editor | Code Style | Kotlin, click on "Set from…" link in the upper
right corner, and select "Prede ned style / Kotlin style guide" from the menu.
To verify that your code is formatted according to the style guide, go to the inspection settings and
enable the "Kotlin | Style issues | File is not formatted according to project settings" inspection.
Additional inspections that verify other issues described in the style guide (such as naming
conventions) are enabled by default.
Directory structure
In mixed-language projects, Kotlin source les should reside in the same source root as the Java
source les, and follow the same directory structure (each le should be stored in the directory
corresponding to each package statement).
In pure Kotlin projects, the recommended directory structure is to follow the package structure
with the common root package omitted (e.g. if all the code in the project is in the
"org.example.kotlin" package and its subpackages, les with the "org.example.kotlin" package
should be placed directly under the source root, and les in "org.example.kotlin.foo.bar" should be
in the "foo/bar" subdirectory of the source root).
Source le names
If a Kotlin le contains a single class (potentially with related top-level declarations), its name
should be the same as the name of the class, with the .kt extension appended. If a le contains
multiple classes, or only top-level declarations, choose a name describing what the le contains,
and name the le accordingly. Use camel humps with an uppercase rst letter (e.g.
ProcessDeclarations.kt ).
57
The name of the le should describe what the code in the le does. Therefore, you should avoid
using meaningless words such as "Util" in le names.
Source le organization
Placing multiple declarations (classes, top-level functions or properties) in the same Kotlin source
le is encouraged as long as these declarations are closely related to each other semantically and
the le size remains reasonable (not exceeding a few hundred lines).
In particular, when de ning extension functions for a class which are relevant for all clients of this
class, put them in the same le where the class itself is de ned. When de ning extension functions
that make sense only for a speci c client, put them next to the code of that client. Do not create
les just to hold "all extensions of Foo".
Class layout
Do not sort the method declarations alphabetically or by visibility, and do not separate regular
methods from extension methods. Instead, put related stu together, so that someone reading the
class from top to bottom would be able to follow the logic of what's happening. Choose an order
(either higher-level stu rst, or vice versa) and stick to it.
Put nested classes next to the code that uses those classes. If the classes are intended to be used
externally and aren't referenced inside the class, put them in the end, after the companion object.
When implementing an interface, keep the implementing members in the same order as members
of the interface (if necessary, interspersed with additional private methods used for the
implementation)
Overload layout
Naming rules
Kotlin follows the Java naming conventions. In particular:
58
Names of packages are always lower case and do not use underscores
( org.example.myproject ). Using multi-word names is generally discouraged, but if you do
need to use multiple words, you can either simply concatenate them together or use camel humps
( org.example.myProject ).
Names of classes and objects start with an upper case letter and use camel humps:
Function names
Names of functions, properties and local variables start with a lower case letter and use camel
humps and no underscores:
Exception: factory functions used to create instances of classes can have the same name as the
class being created:
In tests (and only in tests), it's acceptable to use method names with spaces enclosed in backticks.
(Note that such method names are currently not supported by the Android runtime.) Underscores
in method names are also allowed in test code.
class MyTestCase {
@Test fun `ensure everything works`() { ... }
Property names
Names of constants (properties marked with const , or top-level or object val properties with
no custom get function that hold deeply immutable data) should use uppercase underscore-
separated names:
Names of top-level or object properties which hold objects with behavior or mutable data should
use regular camel-hump names:
59
val mutableCollection: MutableSet<String> = HashSet()
Names of properties holding references to singleton objects can use the same naming style as
object declarations:
For enum constants, it's OK to use either uppercase underscore-separated names ( enum class
Color { RED, GREEN } ) or regular camel-humps names starting with an uppercase letter,
depending on the usage.
If a class has two properties which are conceptually the same but one is part of a public API and
another is an implementation detail, use an underscore as the pre x for the name of the private
property:
class C {
private val _elementList = mutableListOf<Element>()
The name of a class is usually a noun or a noun phrase explaining what the class is: List ,
PersonReader .
The name of a method is usually a verb or a verb phrase saying what the method does: close ,
readPersons . The name should also suggest if the method is mutating the object or returning a
new one. For instance sort is sorting a collection in place, while sorted is returning a sorted
copy of the collection.
The names should make it clear what the purpose of the entity is, so it's best to avoid using
meaningless words ( Manager , Wrapper etc.) in names.
When using an acronym as part of a declaration name, capitalize it if it consists of two letters
( IOStream ); capitalize only the rst letter if it is longer ( XmlFormatter , HttpInputStream ).
Formatting
In most cases, Kotlin follows the Java coding conventions.
For curly braces, put the opening brace in the end of the line where the construct begins, and the
closing brace on a separate line aligned horizontally with the opening construct.
60
if (elements != null) {
for (element in elements) {
// ...
}
}
(Note: In Kotlin, semicolons are optional, and therefore line breaks are signi cant. The language
design assumes Java-style braces, and you may encounter surprising behavior if you try to use a
di erent formatting style.)
Horizontal whitespace
Put spaces around binary operators ( a + b ). Exception: don't put spaces around the "range to"
operator ( 0..i ).
Put spaces between control ow keywords ( if , when , for and while ) and the corresponding
opening parenthesis.
Do not put a space before an opening parenthesis in a primary constructor declaration, method
declaration or method call.
fun bar() {
foo(1)
}
Do not put spaces around angle brackets used to specify type parameters: class Map<K, V> {
... }
As a general rule, avoid horizontal alignment of any kind. Renaming an identi er to a name with a
di erent length should not a ect the formatting of either the declaration or any of the usages.
Colon
61
— when it's used to separate a type and a supertype;
— when delegating to a superclass constructor or a di erent constructor of the same class;
— after the object keyword.
Don't put a space before : when it separates a declaration and its type.
Classes with a few primary constructor parameters can be written in a single line:
Classes with longer headers should be formatted so that each primary constructor parameter is in
a separate line with indentation. Also, the closing parenthesis should be on a new line. If we use
inheritance, then the superclass constructor call or list of implemented interfaces should be
located on the same line as the parenthesis:
class Person(
id: Int,
name: String,
surname: String
) : Human(id, name) { ... }
For multiple interfaces, the superclass constructor call should be located rst and then each
interface should be located in a di erent line:
class Person(
id: Int,
name: String,
surname: String
) : Human(id, name),
KotlinMaker { ... }
For classes with a long supertype list, put a line break after the colon and align all supertype names
horizontally:
62
class MyFavouriteVeryLongClassHolder :
MyLongHolder<MyFavouriteVeryLongClass>(),
SomeOtherInterface,
AndAnotherOne {
To clearly separate the class header and body when the class header is long, either put a blank line
following the class header (as in the example above), or put the opening curly brace on a separate
line:
class MyFavouriteVeryLongClassHolder :
MyLongHolder<MyFavouriteVeryLongClass>(),
SomeOtherInterface,
AndAnotherOne
{
fun foo() { ... }
}
Rationale: This ensures that properties declared in the primary constructor have the same
indentation as properties declared in the body of a class.
Modi ers
If a declaration has multiple modi ers, always put them in the following order:
@Named("Foo")
private val foo: Foo
Unless you're working on a library, omit redundant modi ers (e.g. public ).
Annotation formatting
63
Annotations are typically placed on separate lines, before the declaration to which they are
attached, and with the same indentation:
@Target(AnnotationTarget.PROPERTY)
annotation class JsonExclude
@JsonExclude @JvmField
var x: String
A single annotation without arguments may be placed on the same line as the corresponding
declaration:
File annotations
File annotations are placed after the le comment (if any), before the package statement, and are
separated from package with a blank line (to emphasize the fact that they target the le and not
the package).
package foo.bar
Function formatting
If the function signature doesn't t on a single line, use the following syntax:
fun longMethodName(
argument: ArgumentType = defaultValue,
argument2: AnotherArgumentType
): ReturnType {
// body
}
Prefer using an expression body for functions with the body consisting of a single expression.
64
If the function has an expression body that doesn't t in the same line as the declaration, put the =
sign on the rst line. Indent the expression body by 4 spaces.
Property formatting
For more complex properties, always put get and set keywords on separate lines:
For properties with an initializer, if the initializer is long, add a line break after the equals sign and
indent the initializer by four spaces:
If the condition of an if or when statement is multiline, always use curly braces around the body
of the statement. Indent each subsequent line of the condition by 4 spaces relative to statement
begin. Put the closing parentheses of the condition together with the opening curly brace on a
separate line:
if (!component.isSyncing &&
!hasAnyKotlinRuntimeInScope(module)
) {
return createKotlinNotConfiguredPanel(module)
}
Rationale: Tidy alignment and clear separation of condition and statement body
Put the else , catch , finally keywords, as well as the while keyword of a do/while loop, on
the same line as the preceding curly brace:
if (condition) {
// body
} else {
// else part
}
try {
// body
} finally {
// cleanup
}
65
In a when statement, if a branch is more than a single line, consider separating it from adjacent
case blocks with a blank line:
Put short branches on the same line as the condition, without braces.
when (foo) {
true -> bar() // good
false -> { baz() } // bad
}
In long argument lists, put a line break after the opening parenthesis. Indent arguments by 4
spaces. Group multiple closely related arguments on the same line.
drawSquare(
x = 10, y = 10,
width = 100, height = 100,
fill = true
)
Put spaces around the = sign separating the argument name and value.
When wrapping chained calls, put the . character or the ?. operator on the next line, with a
single indent:
The rst call in the chain usually should have a line break before it, but it's OK to omit it if the code
makes more sense that way.
Lambda formatting
In lambda expressions, spaces should be used around the curly braces, as well as around the arrow
which separates the parameters from the body. If a call takes a single lambda, it should be passed
outside of parentheses whenever possible.
66
list.filter { it > 10 }
If assigning a label for a lambda, do not put a space between the label and the opening curly brace:
fun foo() {
ints.forEach lit@{
// ...
}
}
When declaring parameter names in a multiline lambda, put the names on the rst line, followed
by the arrow and the newline:
If the parameter list is too long to t on a line, put the arrow on a separate line:
foo {
context: Context,
environment: Env
->
context.configureEnv(environment)
}
Documentation comments
For longer documentation comments, place the opening /** on a separate line and begin each
subsequent line with an asterisk:
/**
* This is a documentation comment
* on multiple lines.
*/
Generally, avoid using @param and @return tags. Instead, incorporate the description of
parameters and return values directly into the documentation comment, and add links to
parameters wherever they are mentioned. Use @param and @return only when a lengthy
description is required which doesn't t into the ow of the main text.
67
// Avoid doing this:
/**
* Returns the absolute value of the given number.
* @param number The number to return the absolute value for.
* @return The absolute value.
*/
fun abs(number: Int) = ...
// Do this instead:
/**
* Returns the absolute value of the given [number].
*/
fun abs(number: Int) = ...
Unit
Semicolons
String templates
Don't use curly braces when inserting a simple variable into a string template. Use curly braces only
for longer expressions.
Immutability
Prefer using immutable data to mutable. Always declare local variables and properties as val
rather than var if they are not modi ed after initialization.
Always use immutable collection interfaces ( Collection , List , Set , Map ) to declare
collections which are not mutated. When using factory functions to create collection instances,
always use functions that return immutable collection types when possible:
68
// Bad: use of mutable collection type for value which will not be mutated
fun validateValue(actualValue: String, allowedValues: HashSet<String>) { ... }
Prefer declaring functions with default parameter values to declaring overloaded functions.
// Bad
fun foo() = foo("a")
fun foo(a: String) { ... }
// Good
fun foo(a: String = "a") { ... }
Type aliases
If you have a functional type or a type with type parameters which is used multiple times in a
codebase, prefer de ning a type alias for it:
Lambda parameters
In lambdas which are short and not nested, it's recommended to use the it convention instead of
declaring the parameter explicitly. In nested lambdas with parameters, parameters should be
always declared explicitly.
Returns in a lambda
Avoid using multiple labeled returns in a lambda. Consider restructuring the lambda so that it will
have a single exit point. If that's not possible or not clear enough, consider converting the lambda
into an anonymous function.
Named arguments
Use the named argument syntax when a method takes multiple parameters of the same primitive
type, or for parameters of Boolean type, unless the meaning of all parameters is absolutely clear
from context.
69
drawSquare(x = 10, y = 10, width = 100, height = 100, fill = true)
return when(x) {
0 -> "zero"
else -> "nonzero"
}
if (x)
return foo()
else
return bar()
when(x) {
0 -> return "zero"
else -> return "nonzero"
}
if versus when
when (x) {
null -> ...
else -> ...
}
If you need to use a nullable Boolean in a conditional statement, use if (value == true) or
if (value == false) checks.
Using loops
Prefer using higher-order functions ( filter , map etc.) to loops. Exception: forEach (prefer
using a regular for loop instead, unless the receiver of forEach is nullable or forEach is used
as part of a longer call chain).
70
When making a choice between a complex expression using multiple higher-order functions and a
loop, understand the cost of the operations being performed in each case and keep performance
considerations in mind.
Loops on ranges
Using strings
Prefer to use multiline strings instead of embedding \n escape sequences into regular string
literals.
To maintain indentation in multiline strings, use trimIndent when the resulting string does not
require any internal indentation, or trimMargin when internal indentation is required:
assertEquals(
"""
Foo
Bar
""".trimIndent(),
value
)
Functions vs Properties
In some cases functions with no arguments might be interchangeable with read-only properties.
Although the semantics are similar, there are some stylistic conventions on when to prefer one to
another.
71
Use extension functions liberally. Every time you have a function that works primarily on an object,
consider making it an extension function accepting that object as a receiver. To minimize API
pollution, restrict the visibility of extension functions as much as it makes sense. As necessary, use
local extension functions, member extension functions, or top-level extension functions with
private visibility.
Using in x functions
Declare a function as in x only when it works on two objects which play a similar role. Good
examples: and , to , zip . Bad example: add .
Factory functions
If you declare a factory function for a class, avoid giving it the same name as the class itself. Prefer
using a distinct name making it clear why the behavior of the factory function is special. Only if
there is really no special semantics, you can use the same name as the class.
Example:
If you have an object with multiple overloaded constructors that don't call di erent superclass
constructors and can't be reduced to a single constructor with default argument values, prefer to
replace the overloaded constructors with factory functions.
Platform types
A public function/method returning an expression of a platform type must declare its Kotlin type
explicitly:
Any property (package-level or class-level) initialised with an expression of a platform type must
declare its Kotlin type explicitly:
class Person {
val name: String = MyJavaApi.getProperty("name")
}
A local value initialised with an expression of a platform type may or may not have a type
declaration:
72
fun main() {
val name = MyJavaApi.getProperty("name")
println(name)
}
Kotlin provides a variety of functions to execute a block of code in the context of a given object. To
choose the correct function, consider the following:
— Are you calling methods on multiple objects in the block, or passing the instance of the context
object as an argument? If you are, use one of the functions that allows you to access the context
object as it , not this ( also or let ). Use also if the receiver is not used at all in the
block.
— What should the result of the call be? If the result needs to be the context object, use apply or
also . If you need to return a value from the block, use with , let or run
73
// Return value is context object
class Baz {
val foo: Bar = createBar().apply {
color = RED // Accessing only properties of Bar
text = "Foo"
}
}
— Is the context object nullable, or is it evaluated as a result of a call chain? If it is, use apply ,
let or run . Otherwise, use with or also .
— Always explicitly specify member visibility (to avoid accidentally exposing declarations as public
API)
— Always explicitly specify function return types and property types (to avoid accidentally changing
the return type when the implementation changes)
— Provide KDoc comments for all public members, with the exception of overrides that do not
require any new documentation (to support generating documentation for the library)
74
Basics
Basic Types
In Kotlin, everything is an object in the sense that we can call member functions and properties on
any variable. Some of the types can have a special internal representation - for example, numbers,
characters and booleans can be represented as primitive values at runtime - but to the user they
look like ordinary classes. In this section we describe the basic types used in Kotlin: numbers,
characters, booleans, arrays, and strings.
Numbers
Kotlin handles numbers in a way close to Java, but not exactly the same. For example, there are no
implicit widening conversions for numbers, and literals are slightly di erent in some cases.
Kotlin provides the following built-in types representing numbers (this is close to Java):
Literal Constants
There are the following kinds of literal constants for integral values:
— Decimals: 123
— Hexadecimals: 0x0F
— Binaries: 0b00001011
75
— Floats are tagged by f or F : 123.5f
Representation
On the Java platform, numbers are physically stored as JVM primitive types, unless we need a
nullable number reference (e.g. Int? ) or generics are involved. In the latter cases numbers are
boxed.
Explicit Conversions
Due to di erent representations, smaller types are not subtypes of bigger ones. If they were, we
would have troubles of the following sort:
So equality would have been lost silently all over the place, not to mention identity.
As a consequence, smaller types are NOT implicitly converted to bigger types. This means that we
cannot assign a value of type Byte to an Int variable without an explicit conversion
76
We can use explicit conversions to widen numbers
— toByte(): Byte
— toShort(): Short
— toInt(): Int
— toLong(): Long
— toFloat(): Float
— toDouble(): Double
— toChar(): Char
Absence of implicit conversions is rarely noticeable because the type is inferred from the context,
and arithmetical operations are overloaded for appropriate conversions, for example
Operations
Kotlin supports the standard set of arithmetical operations over numbers, which are declared as
members of appropriate classes (but the compiler optimizes the calls down to the corresponding
instructions). See Operator overloading.
As of bitwise operations, there're no special characters for them, but just named functions that can
be called in in x form, for example:
Here is the complete list of bitwise operations (available for Int and Long only):
— or(bits) – bitwise or
77
— Equality checks: a == b and a != b
When the operands a and b are statically known to be Float or Double or their nullable
counterparts (the type is declared or inferred or is a result of a smart cast), the operations on the
numbers and the range that they form follow the IEEE 754 Standard for Floating-Point Arithmetic.
However, to support generic use cases and provide total ordering, when the operands are not
statically typed as oating point numbers (e.g. Any , Comparable<...> , a type parameter), the
operations use the equals and compareTo implementations for Float and Double , which
disagree with the standard, so that:
Characters
Characters are represented by the type Char . They can not be treated directly as numbers
Character literals go in single quotes: '1' . Special characters can be escaped using a backslash.
The following escape sequences are supported: \t , \b , \n , \r , \' , \" , \\ and \$ . To
encode any other character, use the Unicode escape sequence syntax: '\uFF00' .
Like numbers, characters are boxed when a nullable reference is needed. Identity is not preserved
by the boxing operation.
Booleans
The type Boolean represents booleans, and has two values: true and false.
78
— || – lazy disjunction
— ! - negation
Arrays
Arrays in Kotlin are represented by the Array class, that has get and set functions (that turn
into [] by operator overloading conventions), and size property, along with a few other useful
member functions:
To create an array, we can use a library function arrayOf() and pass the item values to it, so that
arrayOf(1, 2, 3) creates an array [1, 2, 3] . Alternatively, the arrayOfNulls() library
function can be used to create an array of a given size lled with null elements.
Another option is to use the Array constructor that takes the array size and the function that can
return the initial value of each array element given its index:
As we said above, the [] operation stands for calls to member functions get() and set() .
Note: unlike Java, arrays in Kotlin are invariant. This means that Kotlin does not let us assign an
Array<String> to an Array<Any> , which prevents a possible runtime failure (but you can use
Array<out Any> , see Type Projections).
Kotlin also has specialized classes to represent arrays of primitive types without boxing overhead:
ByteArray , ShortArray , IntArray and so on. These classes have no inheritance relation to
the Array class, but they have the same set of methods and properties. Each of them also has a
corresponding factory function:
Unsigned integers
Unsigned types are available only since Kotlin 1.3 and currently are experimental. See
details below
79
Kotlin introduces following types for unsigned integers:
Note that changing type from unsigned type to signed counterpart (and vice versa) is a
binary incompatible change
Unsigned types are implemented using another experimental feature, namely inline classes.
Specialized classes
Same as for primitives, each of unsigned type has corresponding type that represents array,
specialized for that unsigned type:
Same as for signed integer arrays, they provide similar API to Array class without boxing
overhead.
Also, ranges and progressions supported for UInt and ULong by classes
kotlin.ranges.UIntRange , kotlin.ranges.UIntProgression ,
kotlin.ranges.ULongRange , kotlin.ranges.ULongProgression
Literals
To make unsigned integers easier to use, Kotlin provides an ability to tag an integer literal with a
su x indicating a speci c unsigned type (similarly to Float/Long):
— su xes u and U tag literal as unsigned. Exact type will be determined based on the expected
type. If no expected type is provided, UInt or ULong will be chosen based on the size of
literal
80
val b: UByte = 1u // UByte, expected type provided
val s: UShort = 1u // UShort, expected type provided
val l: ULong = 1u // ULong, expected type provided
val a = 1UL // ULong, even though no expected type provided and constant fits into UInt
The design of unsigned types is experimental, meaning that this feature is moving fast and no
compatibility guarantees are given. When using unsigned arithmetics in Kotlin 1.3+, warning will be
reported, indicating that this feature is experimental. To remove warning, you have to opt-in for
experimental usage of unsigned types.
There are two possible ways to opt-in for unsigned types: with marking your API as experimental
too, or without doing that.
— to propagate experimentality, either annotate declarations which use unsigned integers with
@ExperimentalUnsignedTypes or pass -
Xexperimental=kotlin.ExperimentalUnsignedTypes to the compiler (note that the
latter will make all declaration in compiled module experimental)
— to opt-in without propagating experimentality, either annotate declarations with
@UseExperimental(ExperimentalUnsignedTypes::class) or pass -Xuse-
experimental=kotlin.ExperimentalUnsignedTypes
It's up to you to decide if your clients have to explicitly opt-in into usage of your API, but bear in
mind that unsigned types are an experimental feature, so API which uses them can be suddenly
broken due to changes in language.
Further discussion
See language proposal for unsigned types for technical details and further discussion.
Strings
Strings are represented by the type String . Strings are immutable. Elements of a string are
characters that can be accessed by the indexing operation: s[i] . A string can be iterated over
with a for-loop:
for (c in str) {
println(c)
}
81
You can concatenate strings using the + operator. This also works for concatenating strings with
values of other types, as long as the rst element in the expression is a string:
val s = "abc" + 1
println(s + "def")
Note that in most cases using string templates or raw strings is preferable to string concatenation.
String Literals
Kotlin has two types of string literals: escaped strings that may have escaped characters in them
and raw strings that can contain newlines and arbitrary text. An escaped string is very much like a
Java string:
Escaping is done in the conventional way, with a backslash. See Characters above for the list of
supported escape sequences.
A raw string is delimited by a triple quote ( """ ), contains no escaping and can contain newlines
and any other characters:
By default | is used as margin pre x, but you can choose another character and pass it as a
parameter, like trimMargin(">") .
String Templates
Strings may contain template expressions, i.e. pieces of code that are evaluated and whose results
are concatenated into the string. A template expression starts with a dollar sign ($) and consists of
either a simple name:
val i = 10
println("i = $i") // prints "i = 10"
val s = "abc"
println("$s.length is ${s.length}") // prints "abc.length is 3"
82
Templates are supported both inside raw strings and inside escaped strings. If you need to
represent a literal $ character in a raw string (which doesn't support backslash escaping), you can
use the following syntax:
83
Packages
A source le may start with a package declaration:
package foo.bar
// ...
All the contents (such as classes and functions) of the source le are contained by the package
declared. So, in the example above, the full name of baz() is foo.bar.baz , and the full name
of Goo is foo.bar.Goo .
If the package is not speci ed, the contents of such a le belong to "default" package that has no
name.
Default Imports
A number of packages are imported into every Kotlin le by default:
— kotlin.*
— kotlin.annotation.*
— kotlin.collections.*
— kotlin.comparisons.* (since 1.1)
— kotlin.io.*
— kotlin.ranges.*
— kotlin.sequences.*
— kotlin.text.*
— JVM:
— java.lang.*
— kotlin.jvm.*
— JS:
— kotlin.js.*
Imports
Apart from the default imports, each le may contain its own import directives. Syntax for imports
is described in the grammar.
84
or all the accessible contents of a scope (package, class, object etc):
If there is a name clash, we can disambiguate by using as keyword to locally rename the clashing
entity:
The import keyword is not restricted to importing classes; you can also use it to import other
declarations:
Unlike Java, Kotlin does not have a separate "import static" syntax; all of these declarations are
imported using the regular import keyword.
85
Control Flow: if, when, for, while
If Expression
In Kotlin, if is an expression, i.e. it returns a value. Therefore there is no ternary operator
(condition ? then : else), because ordinary if works ne in this role.
// Traditional usage
var max = a
if (a < b) max = b
// With else
var max: Int
if (a > b) {
max = a
} else {
max = b
}
// As expression
val max = if (a > b) a else b
if branches can be blocks, and the last expression is the value of a block:
If you're using if as an expression rather than a statement (for example, returning its value or
assigning it to a variable), the expression is required to have an else branch.
When Expression
when replaces the switch operator of C-like languages. In the simplest form it looks like this
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> { // Note the block
print("x is neither 1 nor 2")
}
}
when matches its argument against all branches sequentially until some branch condition is
satis ed. when can be used either as an expression or as a statement. If it is used as an expression,
the value of the satis ed branch becomes the value of the overall expression. If it is used as a
statement, the values of individual branches are ignored. (Just like with if, each branch can be a
block, and its value is the value of the last expression in the block.)
86
The else branch is evaluated if none of the other branch conditions are satis ed. If when is used
as an expression, the else branch is mandatory, unless the compiler can prove that all possible
cases are covered with branch conditions (as, for example, with enum class entries and sealed
class subtypes).
If many cases should be handled in the same way, the branch conditions may be combined with a
comma:
when (x) {
0, 1 -> print("x == 0 or x == 1")
else -> print("otherwise")
}
when (x) {
parseInt(s) -> print("s encodes x")
else -> print("s does not encode x")
}
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
Another possibility is to check that a value is or !is of a particular type. Note that, due to smart
casts, you can access the methods and properties of the type without any extra checks.
when can also be used as a replacement for an if-else if chain. If no argument is supplied, the
branch conditions are simply boolean expressions, and a branch is executed when its condition is
true:
when {
x.isOdd() -> print("x is odd")
x.isEven() -> print("x is even")
else -> print("x is funny")
}
Since Kotlin 1.3, it is possible to capture when subject in a variable using following syntax:
fun Request.getBody() =
when (val response = executeRequest()) {
is Success -> response.body
is HttpError -> throw HttpException(response.status)
}
87
Scope of variable, introduced in when subject, is restricted to when body.
For Loops
for loop iterates through anything that provides an iterator. This is equivalent to the foreach
loop in languages like C#. The syntax is as follows:
As mentioned before, for iterates through anything that provides an iterator, i.e.
for (i in 1..3) {
println(i)
}
for (i in 6 downTo 0 step 2) {
println(i)
}
A for loop over a range or an array is compiled to an index-based loop that does not create an
iterator object.
If you want to iterate through an array or a list with an index, you can do it this way:
for (i in array.indices) {
println(array[i])
}
While Loops
88
while and do..while work as usual
while (x > 0) {
x--
}
do {
val y = retrieveData()
} while (y != null) // y is visible here!
89
Returns and Jumps
Kotlin has three structural jump expressions:
— return. By default returns from the nearest enclosing function or anonymous function.
A break quali ed with a label jumps to the execution point right after the loop marked with that
label. A continue proceeds to the next iteration of that loop.
Return at Labels
With function literals, local functions and object expression, functions can be nested in Kotlin.
Quali ed returns allow us to return from an outer function. The most important use case is
returning from a lambda expression. Recall that when we write this:
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return // non-local return directly to the caller of foo()
print(it)
}
println("this point is unreachable")
}
The return-expression returns from the nearest enclosing function, i.e. foo . (Note that such non-
local returns are supported only for lambda expressions passed to inline functions.) If we need to
return from a lambda expression, we have to label it and qualify the return:
90
fun foo() {
listOf(1, 2, 3, 4, 5).forEach lit@{
if (it == 3) return@lit // local return to the caller of the lambda, i.e. the
forEach loop
print(it)
}
print(" done with explicit label")
}
Now, it returns only from the lambda expression. Oftentimes it is more convenient to use implicit
labels: such a label has the same name as the function to which the lambda is passed.
fun foo() {
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@forEach // local return to the caller of the lambda, i.e. the
forEach loop
print(it)
}
print(" done with implicit label")
}
Alternatively, we can replace the lambda expression with an anonymous function. A return
statement in an anonymous function will return from the anonymous function itself.
fun foo() {
listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {
if (value == 3) return // local return to the caller of the anonymous fun, i.e.
the forEach loop
print(value)
})
print(" done with anonymous function")
}
Note that the use of local returns in previous three examples is similar to the use of continue in
regular loops. There is no direct equivalent for break, but it can be simulated by adding another
nesting lambda and non-locally returning from it:
fun foo() {
run loop@{
listOf(1, 2, 3, 4, 5).forEach {
if (it == 3) return@loop // non-local return from the lambda passed to run
print(it)
}
}
print(" done with nested loop")
}
When returning a value, the parser gives preference to the quali ed return, i.e.
return@a 1
means "return 1 at label @a " and not "return a labeled expression (@a 1) ".
91
Classes and Objects
Classes and Inheritance
Classes
Classes in Kotlin are declared using the keyword class:
The class declaration consists of the class name, the class header (specifying its type parameters,
the primary constructor etc.) and the class body, surrounded by curly braces. Both the header and
the body are optional; if the class has no body, curly braces can be omitted.
class Empty
Constructors
A class in Kotlin can have a primary constructor and one or more secondary constructors. The
primary constructor is part of the class header: it goes after the class name (and optional type
parameters).
If the primary constructor does not have any annotations or visibility modi ers, the constructor
keyword can be omitted:
The primary constructor cannot contain any code. Initialization code can be placed in initializer
blocks, which are pre xed with the init keyword.
During an instance initialization, the initializer blocks are executed in the same order as they
appear in the class body, interleaved with the property initializers:
92
class InitOrderDemo(name: String) {
val firstProperty = "First property: $name".also(::println)
init {
println("First initializer block that prints ${name}")
}
init {
println("Second initializer block that prints ${name.length}")
}
}
Note that parameters of the primary constructor can be used in the initializer blocks. They can also
be used in property initializers declared in the class body:
In fact, for declaring properties and initializing them from the primary constructor, Kotlin has a
concise syntax:
class Person(val firstName: String, val lastName: String, var age: Int) { ... }
Much the same way as regular properties, the properties declared in the primary constructor can
be mutable (var) or read-only (val).
If the constructor has annotations or visibility modi ers, the constructor keyword is required,
and the modi ers go before it:
Secondary Constructors
The class can also declare secondary constructors, which are pre xed with constructor:
class Person {
constructor(parent: Person) {
parent.children.add(this)
}
}
If the class has a primary constructor, each secondary constructor needs to delegate to the primary
constructor, either directly or indirectly through another secondary constructor(s). Delegation to
another constructor of the same class is done using the this keyword:
93
Note that code in initializer blocks e ectively becomes part of the primary constructor. Delegation
to the primary constructor happens as the rst statement of a secondary constructor, so the code
in all initializer blocks is executed before the secondary constructor body. Even if the class has no
primary constructor, the delegation still happens implicitly, and the initializer blocks are still
executed:
class Constructors {
init {
println("Init block")
}
constructor(i: Int) {
println("Constructor")
}
}
If a non-abstract class does not declare any constructors (primary or secondary), it will have a
generated primary constructor with no arguments. The visibility of the constructor will be public. If
you do not want your class to have a public constructor, you need to declare an empty primary
constructor with non-default visibility:
NOTE: On the JVM, if all of the parameters of the primary constructor have default values, the
compiler will generate an additional parameterless constructor which will use the default
values. This makes it easier to use Kotlin with libraries such as Jackson or JPA that create class
instances through parameterless constructors.
Creating instances of nested, inner and anonymous inner classes is described in Nested classes.
Class Members
94
— Nested and Inner Classes
— Object Declarations
Inheritance
All classes in Kotlin have a common superclass Any , that is the default superclass for a class with
no supertypes declared:
Note: Any is not java.lang.Object; in particular, it does not have any members other than
equals(), hashCode() and toString(). Please consult the Java interoperability section for
more details.
To declare an explicit supertype, we place the type after a colon in the class header:
If the derived class has a primary constructor, the base class can (and must) be initialized right
there, using the parameters of the primary constructor.
If the class has no primary constructor, then each secondary constructor has to initialize the base
type using the super keyword, or to delegate to another constructor which does that. Note that in
this case di erent secondary constructors can call di erent constructors of the base type:
Overriding Methods
As we mentioned before, we stick to making things explicit in Kotlin. And unlike Java, Kotlin
requires explicit modi ers for overridable members (we call them open) and for overrides:
The override modi er is required for Derived.v() . If it were missing, the compiler would
complain. If there is no open modi er on a function, like Base.nv() , declaring a method with the
same signature in a subclass is illegal, either with override or without it. The open modi er has
no e ect when added on members of a nal class (i.e.. a class with no open modi er).
95
A member marked override is itself open, i.e. it may be overridden in subclasses. If you want to
prohibit re-overriding, use final:
Overriding Properties
You can also override a val property with a var property, but not vice versa. This is allowed
because a val property essentially declares a getter method, and overriding it as a var
additionally declares a setter method in the derived class.
Note that you can use the override keyword as part of the property declaration in a primary
constructor.
interface Foo {
val count: Int
}
During construction of a new instance of a derived class, the base class initialization is done as the
rst step (preceded only by evaluation of the arguments for the base class constructor) and thus
happens before the initialization logic of the derived class is run.
96
open class Base(val name: String) {
class Derived(
name: String,
val lastName: String
) : Base(name.capitalize().also { println("Argument for Base: $it") }) {
It means that, by the time of the base class constructor execution, the properties declared or
overridden in the derived class are not yet initialized. If any of those properties are used in the
base class initialization logic (either directly or indirectly, through another overridden open
member implementation), it may lead to incorrect behavior or a runtime failure. When designing a
base class, you should therefore avoid using open members in the constructors, property
initializers, and init blocks.
Code in a derived class can call its superclass functions and property accessors implementations
using the super keyword:
Inside an inner class, accessing the superclass of the outer class is done with the super keyword
quali ed with the outer class name: super@Outer :
97
class Bar : Foo() {
override fun f() { /* ... */ }
override val x: Int get() = 0
Overriding Rules
In Kotlin, implementation inheritance is regulated by the following rule: if a class inherits many
implementations of the same member from its immediate superclasses, it must override this
member and provide its own implementation (perhaps, using one of the inherited ones). To
denote the supertype from which the inherited implementation is taken, we use super quali ed
by the supertype name in angle brackets, e.g. super<Base> :
open class A {
open fun f() { print("A") }
fun a() { print("a") }
}
interface B {
fun f() { print("B") } // interface members are 'open' by default
fun b() { print("b") }
}
It's ne to inherit from both A and B , and we have no problems with a() and b() since C
inherits only one implementation of each of these functions. But for f() we have two
implementations inherited by C , and thus we have to override f() in C and provide our own
implementation that eliminates the ambiguity.
Abstract Classes
A class and some of its members may be declared abstract. An abstract member does not have
an implementation in its class. Note that we do not need to annotate an abstract class or function
with open – it goes without saying.
98
open class Base {
open fun f() {}
}
Companion Objects
In Kotlin, unlike Java or C#, classes do not have static methods. In most cases, it's recommended to
simply use package-level functions instead.
If you need to write a function that can be called without having a class instance but needs access
to the internals of a class (for example, a factory method), you can write it as a member of an
object declaration inside that class.
Even more speci cally, if you declare a companion object inside your class, you'll be able to call its
members with the same syntax as calling static methods in Java/C#, using only the class name as a
quali er.
99
Properties and Fields
Declaring Properties
Classes in Kotlin can have properties. These can be declared as mutable, using the var keyword or
read-only using the val keyword.
class Address {
var name: String = ...
var street: String = ...
var city: String = ...
var state: String? = ...
var zip: String = ...
}
The initializer, getter and setter are optional. Property type is optional if it can be inferred from the
initializer (or from the getter return type, as shown below).
Examples:
var allByDefault: Int? // error: explicit initializer required, default getter and setter
implied
var initialized = 1 // has type Int, default getter and setter
The full syntax of a read-only property declaration di ers from a mutable one in two ways: it starts
with val instead of var and does not allow a setter:
val simple: Int? // has type Int, default getter, must be initialized in constructor
val inferredType = 1 // has type Int and a default getter
We can de ne custom accessors for a property. If we de ne a custom getter, it will be called every
time we access the property (this allows us to implement a computed property). Here's an example
of a custom getter:
100
If we de ne a custom setter, it will be called every time we assign a value to the property. A custom
setter looks like this:
By convention, the name of the setter parameter is value , but you can choose a di erent name if
you prefer.
Since Kotlin 1.1, you can omit the property type if it can be inferred from the getter:
If you need to change the visibility of an accessor or to annotate it, but don't need to change the
default implementation, you can de ne the accessor without de ning its body:
Backing Fields
Fields cannot be declared directly in Kotlin classes. However, when a property needs a backing
eld, Kotlin provides it automatically. This backing eld can be referenced in the accessors using
the field identi er:
var counter = 0 // Note: the initializer assigns the backing field directly
set(value) {
if (value >= 0) field = value
}
The field identi er can only be used in the accessors of the property.
A backing eld will be generated for a property if it uses the default implementation of at least one
of the accessors, or if a custom accessor references it through the field identi er.
Backing Properties
If you want to do something that does not t into this "implicit backing eld" scheme, you can
always fall back to having a backing property:
101
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null) {
_table = HashMap() // Type parameters are inferred
}
return _table ?: throw AssertionError("Set to null by another thread")
}
In all respects, this is just the same as in Java since access to private properties with default getters
and setters is optimized so that no function call overhead is introduced.
Compile-Time Constants
Properties the value of which is known at compile time can be marked as compile time constants
using the const modi er. Such properties need to ful l the following requirements:
— No custom getter
To handle this case, you can mark the property with the lateinit modi er:
102
The modi er can be used on var properties declared inside the body of a class (not in the
primary constructor, and only when the property does not have a custom getter or setter) and,
since Kotlin 1.2, for top-level properties and local variables. The type of the property or variable
must be non-null, and it must not be a primitive type.
Accessing a lateinit property before it has been initialized throws a special exception that
clearly identi es the property being accessed and the fact that it hasn't been initialized.
To check whether a lateinit var has already been initialized, use .isInitialized on the
reference to that property:
if (foo::bar.isInitialized) {
println(foo.bar)
}
This check is only available for the properties that are lexically accessible, i.e. declared in the same
type or in one of the outer types, or at top level in the same le.
Overriding Properties
See Overriding Properties
Delegated Properties
The most common kind of properties simply reads from (and maybe writes to) a backing eld. On
the other hand, with custom getters and setters one can implement any behaviour of a property.
Somewhere in between, there are certain common patterns of how a property may work. A few
examples: lazy values, reading from a map by a given key, accessing a database, notifying listener
on access, etc.
103
Interfaces
Interfaces in Kotlin are very similar to Java 8. They can contain declarations of abstract methods, as
well as method implementations. What makes them di erent from abstract classes is that
interfaces cannot store state. They can have properties but these need to be abstract or to provide
accessor implementations.
interface MyInterface {
fun bar()
fun foo() {
// optional body
}
}
Implementing Interfaces
A class or object can implement one or more interfaces
Properties in Interfaces
You can declare properties in interfaces. A property declared in an interface can either be abstract,
or it can provide implementations for accessors. Properties declared in interfaces can't have
backing elds, and therefore accessors declared in interfaces can't reference them.
interface MyInterface {
val prop: Int // abstract
fun foo() {
print(prop)
}
}
Interfaces Inheritance
An interface can derive from other interfaces and thus both provide implementations for their
members and declare new functions and properties. Quite naturally, classes implementing such an
interface are only required to de ne the missing implementations:
104
interface Named {
val name: String
}
interface A {
fun foo() { print("A") }
fun bar()
}
interface B {
fun foo() { print("B") }
fun bar() { print("bar") }
}
class C : A {
override fun bar() { print("bar") }
}
class D : A, B {
override fun foo() {
super<A>.foo()
super<B>.foo()
}
Interfaces A and B both declare functions foo() and bar(). Both of them implement foo(), but only B
implements bar() (bar() is not marked abstract in A, because this is the default for interfaces, if the
function has no body). Now, if we derive a concrete class C from A, we, obviously, have to override
bar() and provide an implementation.
However, if we derive D from A and B, we need to implement all the methods which we have
inherited from multiple interfaces, and to specify how exactly D should implement them. This rule
applies both to methods for which we've inherited a single implementation (bar()) and multiple
implementations (foo()).
105
Visibility Modi ers
Classes, objects, interfaces, constructors, functions, properties and their setters can have visibility
modi ers. (Getters always have the same visibility as the property.) There are four visibility
modi ers in Kotlin: private , protected , internal and public . The default visibility, used if
there is no explicit modi er, is public .
Below please nd explanations of how the modi ers apply to di erent types of declaring scopes.
Packages
Functions, properties and classes, objects and interfaces can be declared on the "top-level", i.e.
directly inside a package:
— If you do not specify any visibility modi er, public is used by default, which means that your
declarations will be visible everywhere;
— If you mark a declaration private , it will only be visible inside the le containing the
declaration;
— If you mark it internal , it is visible everywhere in the same module;
Note: to use a visible top-level declaration from another package, you should still import it.
Examples:
— private means visible inside this class only (including all its members);
— internal — any client inside this module who sees the declaring class sees its internal
members;
— public — any client who sees the declaring class sees its public members.
106
NOTE for Java users: outer class does not see private members of its inner classes in Kotlin.
If you override a protected member and do not specify the visibility explicitly, the overriding
member will also have protected visibility.
Examples:
Constructors
To specify a visibility of the primary constructor of a class, use the following syntax (note that you
need to add an explicit constructor keyword):
Here the constructor is private. By default, all constructors are public , which e ectively amounts
to them being visible everywhere where the class is visible (i.e. a constructor of an internal class
is only visible within the same module).
Local declarations
Local variables, functions and classes can not have visibility modi ers.
Modules
The internal visibility modi er means that the member is visible within the same module. More
speci cally, a module is a set of Kotlin les compiled together:
107
— a Maven project;
— a Gradle source set (with the exception that the test source set can access the internal
declarations of main );
— a set of les compiled with one invocation of the <kotlinc> Ant task.
108
Extensions
Kotlin, similar to C# and Gosu, provides the ability to extend a class with new functionality without
having to inherit from the class or use any type of design pattern such as Decorator. This is done
via special declarations called extensions. Kotlin supports extension functions and extension
properties.
Extension Functions
To declare an extension function, we need to pre x its name with a receiver type, i.e. the type being
extended. The following adds a swap function to MutableList<Int> :
The this keyword inside an extension function corresponds to the receiver object (the one that is
passed before the dot). Now, we can call such a function on any MutableList<Int> :
val l = mutableListOf(1, 2, 3)
l.swap(0, 2) // 'this' inside 'swap()' will hold the value of 'l'
Of course, this function makes sense for any MutableList<T> , and we can make it generic:
We declare the generic type parameter before the function name for it to be available in the
receiver type expression. See Generic functions.
We would like to emphasize that extension functions are dispatched statically, i.e. they are not
virtual by receiver type. This means that the extension function being called is determined by the
type of the expression on which the function is invoked, not by the type of the result of evaluating
that expression at runtime. For example:
109
open class C
class D: C()
fun printFoo(c: C) {
println(c.foo())
}
printFoo(D())
This example will print "c", because the extension function being called depends only on the
declared type of the parameter c , which is the C class.
If a class has a member function, and an extension function is de ned which has the same receiver
type, the same name is applicable to given arguments, the member always wins. For example:
class C {
fun foo() { println("member") }
}
However, it's perfectly OK for extension functions to overload member functions which have the
same name but a di erent signature:
class C {
fun foo() { println("member") }
}
Nullable Receiver
Note that extensions can be de ned with a nullable receiver type. Such extensions can be called on
an object variable even if its value is null, and can check for this == null inside the body. This
is what allows you to call toString() in Kotlin without checking for null: the check happens inside the
extension function.
Extension Properties
110
Similarly to functions, Kotlin supports extension properties:
Note that, since extensions do not actually insert members into classes, there's no e cient way for
an extension property to have a backing eld. This is why initializers are not allowed for
extension properties. Their behavior can only be de ned by explicitly providing getters/setters.
Example:
val Foo.bar = 1 // error: initializers are not allowed for extension properties
class MyClass {
companion object { } // will be called "Companion"
}
Just like regular members of the companion object, they can be called using only the class name as
the quali er:
MyClass.foo()
Scope of Extensions
Most of the time we de ne extensions on the top level, i.e. directly under packages:
package foo.bar
To use such an extension outside its declaring package, we need to import it at the call site:
package com.example.usage
111
Inside a class, you can declare extensions for another class. Inside such an extension, there are
multiple implicit receivers - objects members of which can be accessed without a quali er. The
instance of the class in which the extension is declared is called dispatch receiver, and the instance
of the receiver type of the extension method is called extension receiver.
class D {
fun bar() { ... }
}
class C {
fun baz() { ... }
fun D.foo() {
bar() // calls D.bar
baz() // calls C.baz
}
fun caller(d: D) {
d.foo() // call the extension function
}
}
In case of a name con ict between the members of the dispatch receiver and the extension
receiver, the extension receiver takes precedence. To refer to the member of the dispatch receiver
you can use the quali ed this syntax.
class C {
fun D.foo() {
toString() // calls D.toString()
[email protected]() // calls C.toString()
}
}
Extensions declared as members can be declared as open and overridden in subclasses. This
means that the dispatch of such functions is virtual with regard to the dispatch receiver type, but
static with regard to the extension receiver type.
112
open class D { }
class D1 : D() { }
open class C {
open fun D.foo() {
println("D.foo in C")
}
fun caller(d: D) {
d.foo() // call the extension function
}
}
class C1 : C() {
override fun D.foo() {
println("D.foo in C1")
}
fun main() {
C().caller(D()) // prints "D.foo in C"
C1().caller(D()) // prints "D.foo in C1" - dispatch receiver is resolved virtually
C().caller(D1()) // prints "D.foo in C" - extension receiver is resolved statically
}
Note on visibility
Extensions utilize the same visibility of other entities as regular functions declared in the same
scope would. For example:
— An extension declared on top level of a le has access to the other private top-level
declarations in the same le;
— If an extension is declared outside its receiver type, such an extension cannot access the
receiver's private members.
Motivation
In Java, we are used to classes named "*Utils": FileUtils , StringUtils and so on. The famous
java.util.Collections belongs to the same breed. And the unpleasant part about these
Utils-classes is that the code that uses them looks like this:
// Java
Collections.swap(list, Collections.binarySearch(list,
Collections.max(otherList)),
Collections.max(list));
Those class names are always getting in the way. We can use static imports and get this:
113
// Java
swap(list, binarySearch(list, max(otherList)), max(list));
This is a little better, but we have no or little help from the powerful code completion of the IDE. It
would be so much better if we could say:
// Java
list.swap(list.binarySearch(otherList.max()), list.max());
But we don't want to implement all the possible methods inside the class List , right? This is
where extensions help us.
114
Data Classes
We frequently create classes whose main purpose is to hold data. In such a class some standard
functionality and utility functions are often mechanically derivable from the data. In Kotlin, this is
called a data class and is marked as data :
The compiler automatically derives the following members from all properties declared in the
primary constructor:
To ensure consistency and meaningful behavior of the generated code, data classes have to ful ll
the following requirements:
Additionally, the members generation follows these rules with regard to the members inheritance:
Since 1.1, data classes may extend other classes (see Sealed classes for examples).
On the JVM, if the generated class needs to have a parameterless constructor, default values for all
properties have to be speci ed (see Constructors).
115
Properties Declared in the Class Body
Note that the compiler only uses the properties de ned inside the primary constructor for the
automatically generated functions. To exclude a property from the generated implementations,
declare it inside the class body:
Only the property name will be used inside the toString() , equals() , hashCode() , and
copy() implementations, and there will only be one component function component1() . While
two Person objects can have di erent ages, they will be treated as equal.
Copying
It's often the case that we need to copy an object altering some of its properties, but keeping the
rest unchanged. This is what copy() function is generated for. For the User class above, its
implementation would be as follows:
116
Sealed Classes
Sealed classes are used for representing restricted class hierarchies, when a value can have one of
the types from a limited set, but cannot have any other type. They are, in a sense, an extension of
enum classes: the set of values for an enum type is also restricted, but each enum constant exists
only as a single instance, whereas a subclass of a sealed class can have multiple instances which can
contain state.
To declare a sealed class, you put the sealed modi er before the name of the class. A sealed
class can have subclasses, but all of them must be declared in the same le as the sealed class
itself. (Before Kotlin 1.1, the rules were even more strict: classes had to be nested inside the
declaration of the sealed class).
(The example above uses one additional new feature of Kotlin 1.1: the possibility for data classes to
extend other classes, including sealed classes.)
A sealed class is abstract by itself, it cannot be instantiated directly and can have abstract
members.
Sealed classes are not allowed to have non-private constructors (their constructors are private
by default).
Note that classes which extend subclasses of a sealed class (indirect inheritors) can be placed
anywhere, not necessarily in the same le.
The key bene t of using sealed classes comes into play when you use them in a when expression. If
it's possible to verify that the statement covers all cases, you don't need to add an else clause to
the statement. However, this works only if you use when as an expression (using the result) and
not as a statement.
117
Generics
As in Java, classes in Kotlin may have type parameters:
class Box<T>(t: T) {
var value = t
}
In general, to create an instance of such a class, we need to provide the type arguments:
But if the parameters may be inferred, e.g. from the constructor arguments or by some other
means, one is allowed to omit the type arguments:
val box = Box(1) // 1 has type Int, so the compiler figures out that we are talking about
Box<Int>
Variance
One of the most tricky parts of Java's type system is wildcard types (see Java Generics FAQ). And
Kotlin doesn't have any. Instead, it has two other things: declaration-site variance and type
projections.
First, let's think about why Java needs those mysterious wildcards. The problem is explained in
E ective Java, 3rd Edition, Item 31: Use bounded wildcards to increase API exibility. First, generic
types in Java are invariant, meaning that List<String> is not a subtype of List<Object> .
Why so? If List was not invariant, it would have been no better than Java's arrays, since the
following code would have compiled and caused an exception at runtime:
// Java
List<String> strs = new ArrayList<String>();
List<Object> objs = strs; // !!! The cause of the upcoming problem sits here. Java
prohibits this!
objs.add(1); // Here we put an Integer into a list of Strings
String s = strs.get(0); // !!! ClassCastException: Cannot cast Integer to String
So, Java prohibits such things in order to guarantee run-time safety. But this has some implications.
For example, consider the addAll() method from Collection interface. What's the signature
of this method? Intuitively, we'd put it this way:
// Java
interface Collection<E> ... {
void addAll(Collection<E> items);
}
But then, we would not be able to do the following simple thing (which is perfectly safe):
118
// Java
void copyAll(Collection<Object> to, Collection<String> from) {
to.addAll(from);
// !!! Would not compile with the naive declaration of addAll:
// Collection<String> is not a subtype of Collection<Object>
}
(In Java, we learned this lesson the hard way, see E ective Java, 3rd Edition, Item 28: Prefer lists to
arrays)
// Java
interface Collection<E> ... {
void addAll(Collection<? extends E> items);
}
The wildcard type argument ? extends E indicates that this method accepts a collection of
objects of E or some subtype of E , not just E itself. This means that we can safely read E 's from
items (elements of this collection are instances of a subclass of E), but cannot write to it since we
do not know what objects comply to that unknown subtype of E . In return for this limitation, we
have the desired behaviour: Collection<String> is a subtype of Collection<? extends
Object> . In "clever words", the wildcard with an extends-bound (upper bound) makes the type
covariant.
The key to understanding why this trick works is rather simple: if you can only take items from a
collection, then using a collection of String s and reading Object s from it is ne. Conversely, if
you can only put items into the collection, it's OK to take a collection of Object s and put
String s into it: in Java we have List<? super String> a supertype of List<Object> .
The latter is called contravariance, and you can only call methods that take String as an argument
on List<? super String> (e.g., you can call add(String) or set(int, String) ), while if
you call something that returns T in List<T> , you don't get a String , but an Object .
Joshua Bloch calls those objects you only read from Producers, and those you only write to
Consumers. He recommends: "For maximum exibility, use wildcard types on input parameters that
represent producers or consumers", and proposes the following mnemonic:
NOTE: if you use a producer-object, say, List<? extends Foo> , you are not allowed to call
add() or set() on this object, but this does not mean that this object is immutable: for
example, nothing prevents you from calling clear() to remove all items from the list, since
clear() does not take any parameters at all. The only thing guaranteed by wildcards (or other
types of variance) is type safety. Immutability is a completely di erent story.
Declaration-site variance
119
Suppose we have a generic interface Source<T> that does not have any methods that take T as a
parameter, only methods that return T :
// Java
interface Source<T> {
T nextT();
}
// Java
void demo(Source<String> strs) {
Source<Object> objects = strs; // !!! Not allowed in Java
// ...
}
To x this, we have to declare objects of type Source<? extends Object> , which is sort of
meaningless, because we can call all the same methods on such a variable as before, so there's no
value added by the more complex type. But the compiler does not know that.
In Kotlin, there is a way to explain this sort of thing to the compiler. This is called declaration-site
variance: we can annotate the type parameter T of Source to make sure that it is only returned
(produced) from members of Source<T> , and never consumed. To do this we provide the out
modi er:
The general rule is: when a type parameter T of a class C is declared out, it may occur only in out-
position in the members of C , but in return C<Base> can safely be a supertype of C<Derived> .
In "clever words" they say that the class C is covariant in the parameter T , or that T is a
covariant type parameter. You can think of C as being a producer of T 's, and NOT a consumer
of T 's.
The out modi er is called a variance annotation, and since it is provided at the type parameter
declaration site, we talk about declaration-site variance. This is in contrast with Java's use-site
variance where wildcards in the type usages make the types covariant.
In addition to out, Kotlin provides a complementary variance annotation: in. It makes a type
parameter contravariant: it can only be consumed and never produced. A good example of a
contravariant type is Comparable :
120
interface Comparable<in T> {
operator fun compareTo(other: T): Int
}
We believe that the words in and out are self-explaining (as they were successfully used in C# for
quite some time already), thus the mnemonic mentioned above is not really needed, and one can
rephrase it for a higher purpose:
Type projections
It is very convenient to declare a type parameter T as out and avoid trouble with subtyping on the
use site, but some classes can't actually be restricted to only return T 's! A good example of this is
Array:
This class cannot be either co- or contravariant in T . And this imposes certain in exibilities.
Consider the following function:
This function is supposed to copy items from one array to another. Let's try to apply it in practice:
Here we run into the same familiar problem: Array<T> is invariant in T , thus neither of
Array<Int> and Array<Any> is a subtype of the other. Why? Again, because copy might be
doing bad things, i.e. it might attempt to write, say, a String to from , and if we actually passed an
array of Int there, a ClassCastException would have been thrown sometime later.
Then, the only thing we want to ensure is that copy() does not do any bad things. We want to
prohibit it from writing to from , and we can:
121
fun copy(from: Array<out Any>, to: Array<Any>) { ... }
What has happened here is called type projection: we said that from is not simply an array, but a
restricted (projected) one: we can only call those methods that return the type parameter T , in
this case it means that we can only call get() . This is our approach to use-site variance, and
corresponds to Java's Array<? extends Object> , but in a slightly simpler way.
Array<in String> corresponds to Java's Array<? super String> , i.e. you can pass an array
of CharSequence or an array of Object to the fill() function.
Star-projections
Sometimes you want to say that you know nothing about the type argument, but still want to use it
in a safe way. The safe way here is to de ne such a projection of the generic type, that every
concrete instantiation of that generic type would be a subtype of that projection.
— For Foo<out T : TUpper> , where T is a covariant type parameter with the upper bound
TUpper , Foo<*> is equivalent to Foo<out TUpper> . It means that when the T is unknown
you can safely read values of TUpper from Foo<*> .
— For Foo<in T> , where T is a contravariant type parameter, Foo<*> is equivalent to Foo<in
Nothing> . It means there is nothing you can write to Foo<*> in a safe way when T is
unknown.
— For Foo<T : TUpper> , where T is an invariant type parameter with the upper bound
TUpper , Foo<*> is equivalent to Foo<out TUpper> for reading values and to Foo<in
Nothing> for writing values.
If a generic type has several type parameters each of them can be projected independently. For
example, if the type is declared as interface Function<in T, out U> we can imagine the
following star-projections:
Note: star-projections are very much like Java's raw types, but safe.
Generic functions
Not only classes can have type parameters. Functions can, too. Type parameters are placed before
the name of the function:
122
fun <T> singletonList(item: T): List<T> {
// ...
}
To call a generic function, specify the type arguments at the call site after the name of the function:
val l = singletonList<Int>(1)
Type arguments can be omitted if they can be inferred from the context, so the following example
works as well:
val l = singletonList(1)
Generic constraints
The set of all possible types that can be substituted for a given type parameter may be restricted by
generic constraints.
Upper bounds
The most common type of constraint is an upper bound that corresponds to Java's extends
keyword:
The type speci ed after a colon is the upper bound: only a subtype of Comparable<T> may be
substituted for T . For example:
The default upper bound (if none speci ed) is Any? . Only one upper bound can be speci ed
inside the angle brackets. If the same type parameter needs more than one upper bound, we need
a separate where-clause:
Type erasure
The type safety checks that Kotlin performs for generic declaration usages are only done at compile
time. At runtime, the instances of generic types do not hold any information about their actual type
arguments. The type information is said to be erased. For example, the instances of Foo<Bar> and
Foo<Baz?> are erased to just Foo<*> .
123
Therefore, there is no general way to check whether an instance of a generic type was created with
certain type arguments at runtime, and the compiler prohibits such is-checks.
Type casts to generic types with concrete type arguments, e.g. foo as List<String> , cannot be
checked at runtime.
These unchecked casts can be used when type safety is implied by the high-level program logic but
cannot be inferred directly by the compiler. The compiler issues a warning on unchecked casts, and
at runtime, only the non-generic part is checked (equivalent to foo as List<*> ).
The type arguments of generic function calls are also only checked at compile time. Inside the
function bodies, the type parameters cannot be used for type checks, and type casts to type
parameters ( foo as T ) are unchecked. However, rei ed type parameters of inline functions are
substituted by the actual type arguments in the inlined function body at the call sites and thus can
be used for type checks and casts, with the same restrictions for instances of generic types as
described above.
124
Nested and Inner Classes
Classes can be nested in other classes:
class Outer {
private val bar: Int = 1
class Nested {
fun foo() = 2
}
}
Inner classes
A class may be marked as inner to be able to access members of outer class. Inner classes carry a
reference to an object of an outer class:
class Outer {
private val bar: Int = 1
inner class Inner {
fun foo() = bar
}
}
See Quali ed this expressions to learn about disambiguation of this in inner classes.
window.addMouseListener(object: MouseAdapter() {
If the object is an instance of a functional Java interface (i.e. a Java interface with a single abstract
method), you can create it using a lambda expression pre xed with the type of the interface:
125
Enum Classes
The most basic usage of enum classes is implementing type-safe enums:
Each enum constant is an object. Enum constants are separated with commas.
Initialization
Since each enum is an instance of the enum class, they can be initialized as:
Anonymous Classes
Enum constants can also declare their own anonymous classes:
TALKING {
override fun signal() = WAITING
};
with their corresponding methods, as well as overriding base methods. Note that if the enum class
de nes any members, you need to separate the enum constant de nitions from the member
de nitions with a semicolon, just like in Java.
Enum entries cannot contain nested types other than inner classes (deprecated in Kotlin 1.2).
126
enum class IntArithmetics : BinaryOperator<Int>, IntBinaryOperator {
PLUS {
override fun apply(t: Int, u: Int): Int = t + u
},
TIMES {
override fun apply(t: Int, u: Int): Int = t * u
};
Since Kotlin 1.1, it's possible to access the constants in an enum class in a generic way, using the
enumValues<T>() and enumValueOf<T>() functions:
Every enum constant has properties to obtain its name and position in the enum class declaration:
The enum constants also implement the Comparable interface, with the natural order being the
order in which they are de ned in the enum class.
127
Object Expressions and Declarations
Sometimes we need to create an object of a slight modi cation of some class, without explicitly
declaring a new subclass for it. Java handles this case with anonymous inner classes. Kotlin slightly
generalizes this concept with object expressions and object declarations.
Object expressions
To create an object of an anonymous class that inherits from some type (or types), we write:
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) { ... }
If a supertype has a constructor, appropriate constructor parameters must be passed to it. Many
supertypes may be speci ed as a comma-separated list after the colon:
interface B { ... }
If, by any chance, we need "just an object", with no nontrivial supertypes, we can simply say:
fun foo() {
val adHoc = object {
var x: Int = 0
var y: Int = 0
}
print(adHoc.x + adHoc.y)
}
Note that anonymous objects can be used as types only in local and private declarations. If you use
an anonymous object as a return type of a public function or the type of a public property, the
actual type of that function or property will be the declared supertype of the anonymous object, or
Any if you didn't declare any supertype. Members added in the anonymous object will not be
accessible.
128
class C {
// Private function, so the return type is the anonymous object type
private fun foo() = object {
val x: String = "x"
}
fun bar() {
val x1 = foo().x // Works
val x2 = publicFoo().x // ERROR: Unresolved reference 'x'
}
}
Just like Java's anonymous inner classes, code in object expressions can access variables from the
enclosing scope. (Unlike Java, this is not restricted to nal variables.)
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
clickCount++
}
Object declarations
Singleton may be useful in several cases, and Kotlin (after Scala) makes it easy to declare
singletons:
object DataProviderManager {
fun registerDataProvider(provider: DataProvider) {
// ...
}
This is called an object declaration, and it always has a name following the object keyword. Just like
a variable declaration, an object declaration is not an expression, and cannot be used on the right
hand side of an assignment statement.
129
DataProviderManager.registerDataProvider(...)
NOTE: object declarations can't be local (i.e. be nested directly inside a function), but they can be
nested into other object declarations or non-inner classes.
Companion Objects
An object declaration inside a class can be marked with the companion keyword:
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
Members of the companion object can be called by using simply the class name as the quali er:
The name of the companion object can be omitted, in which case the name Companion will be
used:
class MyClass {
companion object { }
}
val x = MyClass.Companion
The name of a class used by itself (not as a quali er to another name) acts as a reference to the
companion object of the class (whether named or not):
class MyClass1 {
companion object Named { }
}
val x = MyClass1
class MyClass2 {
companion object { }
}
val y = MyClass2
Note that, even though the members of companion objects look like static members in other
languages, at runtime those are still instance members of real objects, and can, for example,
implement interfaces:
130
interface Factory<T> {
fun create(): T
}
class MyClass {
companion object : Factory<MyClass> {
override fun create(): MyClass = MyClass()
}
}
However, on the JVM you can have members of companion objects generated as real static
methods and elds, if you use the @JvmStatic annotation. See the Java interoperability section
for more details.
There is one important semantic di erence between object expressions and object declarations:
— object expressions are executed (and initialized) immediately, where they are used;
— object declarations are initialized lazily, when accessed for the rst time;
— a companion object is initialized when the corresponding class is loaded (resolved), matching
the semantics of a Java static initializer.
131
Inline classes
Inline classes are available only since Kotlin 1.3 and currently are experimental. See details
below
Sometimes it is necessary for business logic to create a wrapper around some type. However, it
introduces runtime overhead due to additional heap allocations. Moreover, if the wrapped type is
primitive, performance hit is terrible, because primitive types are usually heavily optimized by the
runtime, while their wrappers don't get any special treatment.
To solve such issues, Kotlin introduces a special kind of class called an inline class , which is
declared by placing an inline modi er before the name of the class:
An inline class must have a single property initialized in the primary constructor. At runtime,
instances of the inline class will be represented using this single property (see details about
runtime representation below):
This is the main feature of inline classes, which inspired the name "inline": data of the class is
"inlined" into its usages (similar to how content of inline functions is inlined to call sites).
Members
Inline classes support some functionality of regular classes. In particular, they are allowed to
declare properties and functions:
fun greet() {
println("Hello, $s")
}
}
fun main() {
val name = Name("Kotlin")
name.greet() // method `greet` is called as a static method
println(name.length) // property getter is called as a static method
}
132
— it follows that inline classes can only have simple computable properties (no
lateinit/delegated properties)
Inheritance
Inline classes are allowed to inherit from interfaces:
interface Printable {
fun prettyPrint(): String
}
fun main() {
val name = Name("Kotlin")
println(name.prettyPrint()) // Still called as a static method
}
It is forbidden for inline classes to participate in a class hierarchy. This means that inline classes
cannot extend other classes and must be final.
Representation
In generated code, the Kotlin compiler keeps a wrapper for each inline class. Inline class instances
can be represented at runtime either as wrappers or as the underlying type. This is similar to how
Int can be represented either as a primitive int or as the wrapper Integer .
The Kotlin compiler will prefer using underlying types instead of wrappers to produce the most
performant and optimized code. However, sometimes it is necessary to keep wrappers around. As
a rule of thumb, inline classes are boxed whenever they are used as another type.
133
interface I
fun main() {
val f = Foo(42)
// below, 'f' first is boxed (while being passed to 'id') and then unboxed (when
returned from 'id')
// In the end, 'c' contains unboxed representation (just '42'), as 'f'
val c = id(f)
}
Because inline classes may be represented both as the underlying value and as a wrapper,
referential equality is pointless for them and is therefore prohibited.
Mangling
Since inline classes are compiled to their underlying type, it may lead to various obscure errors, for
example unexpected platform signature clashes:
To mitigate such issues, functions using inline classes are mangled by adding some stable hashcode
to the function name. Therefore, fun compute(x: UInt) will be represented as public
final void compute-<hashcode>(int x) , which solves the clash problem.
Note that - is an invalid symbol in Java, meaning that it's impossible to call functions which
accept inline classes from Java.
134
However, the crucial di erence is that type aliases are assignment-compatible with their underlying
type (and with other type aliases with the same underlying type), while inline classes are not.
In other words, inline classes introduce a truly new type, contrary to type aliases which only
introduce an alternative name (alias) for an existing type:
fun main() {
val nameAlias: NameTypeAlias = ""
val nameInlineClass: NameInlineClass = NameInlineClass("")
val string: String = ""
To remove the warning you have to opt in to the usage of experimental features by passing the
argument -XXLanguage:+InlineClasses to kotlinc .
compileKotlin {
kotlinOptions.freeCompilerArgs += ["-XXLanguage:+InlineClasses"]
}
See Compiler options in Gradle for details. For Multiplatform Projects settings, see building
Multiplatform Projects with Gradle section.
<configuration>
<args>
<arg>-XXLanguage:+InlineClasses</arg>
</args>
</configuration>
135
See Compiler options in Maven for details.
Further discussion
See this language proposal for inline classes for other technical details and discussion.
136
Delegation
Property Delegation
Delegated properties are described on a separate page: Delegated Properties.
Implementation by Delegation
The Delegation pattern has proven to be a good alternative to implementation inheritance, and
Kotlin supports it natively requiring zero boilerplate code. A class Derived can implement an
interface Base by delegating all of its public members to a speci ed object:
interface Base {
fun print()
}
fun main() {
val b = BaseImpl(10)
Derived(b).print()
}
The by-clause in the supertype list for Derived indicates that b will be stored internally in
objects of Derived and the compiler will generate all the methods of Base that forward to b .
Overrides work as you might expect: the compiler will use your override implementations
instead of those in the delegate object. If we were to add override fun printMessage() {
print("abc") } to Derived , the program would print "abc" instead of "10" when
printMessage is called:
137
interface Base {
fun printMessage()
fun printMessageLine()
}
fun main() {
val b = BaseImpl(10)
Derived(b).printMessage()
Derived(b).printMessageLine()
}
Note, however, that members overridden in this way do not get called from the members of the
delegate object, which can only access its own implementations of the interface members:
interface Base {
val message: String
fun print()
}
fun main() {
val b = BaseImpl(10)
val derived = Derived(b)
derived.print()
println(derived.message)
}
138
Delegated Properties
There are certain common kinds of properties, that, though we can implement them manually
every time we need them, would be very nice to implement once and for all, and put into a library.
Examples include:
— lazy properties: the value gets computed only upon rst access;
— observable properties: listeners get noti ed about changes to this property;
— storing properties in a map, instead of a separate eld for each property.
class Example {
var p: String by Delegate()
}
The syntax is: val/var <property name>: <Type> by <expression> . The expression after
by is the delegate, because get() (and set() ) corresponding to the property will be delegated
to its getValue() and setValue() methods. Property delegates don’t have to implement any
interface, but they have to provide a getValue() function (and setValue() — for vars). For
example:
class Delegate {
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return "$thisRef, thank you for delegating '${property.name}' to me!"
}
When we read from p that delegates to an instance of Delegate , the getValue() function
from Delegate is called, so that its rst parameter is the object we read p from and the second
parameter holds a description of p itself (e.g. you can take its name). For example:
val e = Example()
println(e.p)
This prints:
Example@33a17727, thank you for delegating ‘p’ to me!
Similarly, when we assign to p , the setValue() function is called. The rst two parameters are
the same, and the third holds the value being assigned:
e.p = "NEW"
This prints
NEW has been assigned to ‘p’ in Example@33a17727.
The speci cation of the requirements to the delegated object can be found below.
139
Note that since Kotlin 1.1 you can declare a delegated property inside a function or code block, it
shouldn't necessarily be a member of a class. Below you can nd the example.
Standard Delegates
The Kotlin standard library provides factory methods for several useful kinds of delegates.
Lazy
lazy() is a function that takes a lambda and returns an instance of Lazy<T> which can serve as a
delegate for implementing a lazy property: the rst call to get() executes the lambda passed to
lazy() and remembers the result, subsequent calls to get() simply return the remembered
result.
fun main() {
println(lazyValue)
println(lazyValue)
}
By default, the evaluation of lazy properties is synchronized: the value is computed only in one
thread, and all threads will see the same value. If the synchronization of initialization delegate is
not required, so that multiple threads can execute it simultaneously, pass
LazyThreadSafetyMode.PUBLICATION as a parameter to the lazy() function. And if you're
sure that the initialization will always happen on a single thread, you can use
LazyThreadSafetyMode.NONE mode, which doesn't incur any thread-safety guarantees and the
related overhead.
Observable
Delegates.observable() takes two arguments: the initial value and a handler for
modi cations. The handler gets called every time we assign to the property (after the assignment
has been performed). It has three parameters: a property being assigned to, the old value and the
new one:
140
import kotlin.properties.Delegates
class User {
var name: String by Delegates.observable("<no name>") {
prop, old, new ->
println("$old -> $new")
}
}
fun main() {
val user = User()
user.name = "first"
user.name = "second"
}
If you want to be able to intercept an assignment and "veto" it, use vetoable() instead of
observable() . The handler passed to the vetoable is called before the assignment of a new
property value has been performed.
Delegated properties take values from this map (by the string keys –– names of properties):
This works also for var’s properties if you use a MutableMap instead of read-only Map :
141
fun example(computeFoo: () -> Foo) {
val memoizedFoo by lazy(computeFoo)
The memoizedFoo variable will be computed on the rst access only. If someCondition fails, the
variable won't be computed at all.
For a read-only property (i.e. a val), a delegate has to provide a function named getValue that
takes the following parameters:
— thisRef — must be the same or a supertype of the property owner (for extension properties
— the type being extended);
— property — must be of type KProperty<*> or its supertype.
this function must return the same type as property (or its subtype).
For a mutable property (a var), a delegate has to additionally provide a function named
setValue that takes the following parameters:
getValue() and/or setValue() functions may be provided either as member functions of the
delegate class or extension functions. The latter is handy when you need to delegate property to
an object which doesn't originally provide these functions. Both of the functions need to be
marked with the operator keyword.
The delegate class may implement one of the interfaces ReadOnlyProperty and
ReadWriteProperty containing the required operator methods. These interfaces are
declared in the Kotlin standard library:
Translation Rules
142
Under the hood for every delegated property the Kotlin compiler generates an auxiliary property
and delegates to it. For instance, for the property prop the hidden property prop$delegate is
generated, and the code of the accessors simply delegates to this additional property:
class C {
var prop: Type by MyDelegate()
}
The Kotlin compiler provides all the necessary information about prop in the arguments: the rst
argument this refers to an instance of the outer class C and this::prop is a re ection object
of the KProperty type describing prop itself.
Note that the syntax this::prop to refer a bound callable reference in the code directly is
available only since Kotlin 1.1.
By de ning the provideDelegate operator you can extend the logic of creating the object to
which the property implementation is delegated. If the object used on the right hand side of by
de nes provideDelegate as a member or extension function, that function will be called to
create the property delegate instance.
One of the possible use cases of provideDelegate is to check property consistency when the
property is created, not only in its getter or setter.
For example, if you want to check the property name before binding, you can write something like
this:
143
class ResourceDelegate<T> : ReadOnlyProperty<MyUI, T> {
override fun getValue(thisRef: MyUI, property: KProperty<*>): T { ... }
}
class MyUI {
fun <T> bindResource(id: ResourceID<T>): ResourceLoader<T> { ... }
— thisRef — must be the same or a supertype of the property owner (for extension properties
— the type being extended);
— property — must be of type KProperty<*> or its supertype.
The provideDelegate method is called for each property during the creation of the MyUI
instance, and it performs the necessary validation right away.
Without this ability to intercept the binding between the property and its delegate, to achieve the
same functionality you'd have to pass the property name explicitly, which isn't very convenient:
In the generated code, the provideDelegate method is called to initialize the auxiliary
prop$delegate property. Compare the generated code for the property declaration val prop:
Type by MyDelegate() with the generated code above (when the provideDelegate method
is not present):
144
class C {
var prop: Type by MyDelegate()
}
Note that the provideDelegate method a ects only the creation of the auxiliary property and
doesn't a ect the code generated for getter or setter.
145
Functions and Lambdas
Functions
Function Declarations
Functions in Kotlin are declared using the fun keyword:
Function Usage
Calling functions uses the traditional approach:
Parameters
Function parameters are de ned using Pascal notation, i.e. name: type. Parameters are separated
using commas. Each parameter must be explicitly typed:
Default Arguments
Function parameters can have default values, which are used when a corresponding argument is
omitted. This allows for a reduced number of overloads compared to other languages:
Default values are de ned using the = after type along with the value.
Overriding methods always use the same default parameter values as the base method. When
overriding a method with default parameters values, the default parameter values must be omitted
from the signature:
146
open class A {
open fun foo(i: Int = 10) { ... }
}
class B : A() {
override fun foo(i: Int) { ... } // no default value allowed
}
If a default parameter precedes a parameter with no default value, the default value can be used
only by calling the function with named arguments:
But if a last argument lambda is passed to a function call outside the parentheses, passing no
values for the default parameters is allowed:
Named Arguments
Function parameters can be named when calling functions. This is very convenient when a function
has a high number of parameters or default ones.
reformat(str)
However, when calling it with non-default, the call would look something like:
With named arguments we can make the code much more readable:
reformat(str,
normalizeCase = true,
upperCaseFirstLetter = true,
divideByCamelHumps = false,
wordSeparator = '_'
)
147
and if we do not need all arguments:
When a function is called with both positional and named arguments, all the positional arguments
should be placed before the rst named one. For example, the call f(1, y = 2) is allowed, but
f(x = 1, 2) is not.
Variable number of arguments (vararg) can be passed in the named form by using the spread
operator:
Note that the named argument syntax cannot be used when calling Java functions, because Java
bytecode does not always preserve names of function parameters.
Unit-returning functions
If a function does not return any useful value, its return type is Unit . Unit is a type with only
one value - Unit . This value does not have to be returned explicitly:
The Unit return type declaration is also optional. The above code is equivalent to:
Single-Expression functions
When a function returns a single expression, the curly braces can be omitted and the body is
speci ed after a = symbol:
Explicitly declaring the return type is optional when this can be inferred by the compiler:
148
Functions with block body must always specify return types explicitly, unless it's intended for them
to return Unit , in which case it is optional. Kotlin does not infer return types for functions with
block bodies because such functions may have complex control ow in the body, and the return
type will be non-obvious to the reader (and sometimes even for the compiler).
A parameter of a function (normally the last one) may be marked with vararg modi er:
Inside a function a vararg -parameter of type T is visible as an array of T , i.e. the ts variable in
the example above has type Array<out T> .
Only one parameter may be marked as vararg . If a vararg parameter is not the last one in the
list, values for the following parameters can be passed using the named argument syntax, or, if the
parameter has a function type, by passing a lambda outside parentheses.
When we call a vararg -function, we can pass arguments one-by-one, e.g. asList(1, 2, 3) , or,
if we already have an array and want to pass its contents to the function, we use the spread
operator (pre x the array with * ):
val a = arrayOf(1, 2, 3)
val list = asList(-1, 0, *a, 4)
In x notation
Functions marked with the infix keyword can also be called using the in x notation (omitting the
dot and the parentheses for the call). In x functions must satisfy the following requirements:
// is the same as
1.shl(2)
149
In x function calls have lower precedence than the arithmetic operators, type casts, and
the rangeTo operator. The following expressions are equivalent:
On the other hand, in x function call's precedence is higher than that of the boolean
operators && and ||, is- and in-checks, and some other operators. These expressions are
equivalent as well:
See the Grammar reference for the complete operators precedence hierarchy.
Note that in x functions always require both the receiver and the parameter to be speci ed. When
you're calling a method on the current receiver using the in x notation, you need to use this
explicitly; unlike regular method calls, it cannot be omitted. This is required to ensure
unambiguous parsing.
class MyStringCollection {
infix fun add(s: String) { ... }
fun build() {
this add "abc" // Correct
add("abc") // Correct
add "abc" // Incorrect: the receiver must be specified
}
}
Function Scope
In Kotlin functions can be declared at top level in a le, meaning you do not need to create a class
to hold a function, which you are required to do in languages such as Java, C# or Scala. In addition
to top level functions, Kotlin functions can also be declared local, as member functions and
extension functions.
Local Functions
150
fun dfs(graph: Graph) {
fun dfs(current: Vertex, visited: Set<Vertex>) {
if (!visited.add(current)) return
for (v in current.neighbors)
dfs(v, visited)
}
dfs(graph.vertices[0], HashSet())
}
Local function can access local variables of outer functions (i.e. the closure), so in the case above,
the visited can be a local variable:
dfs(graph.vertices[0])
}
Member Functions
class Sample() {
fun foo() { print("Foo") }
}
For more information on classes and overriding members see Classes and Inheritance.
Generic Functions
Functions can have generic parameters which are speci ed using angle brackets before the
function name:
Inline Functions
Inline functions are explained here.
Extension Functions
Extension functions are explained in their own section.
151
Higher-Order Functions and Lambdas
Higher-Order functions and Lambdas are explained in their own section.
This code calculates the xpoint of cosine, which is a mathematical constant. It simply calls Math.cos
repeatedly starting at 1.0 until the result doesn't change any more, yielding a result of
0.7390851332151611 for the speci ed eps precision. The resulting code is equivalent to this more
traditional style:
To be eligible for the tailrec modi er, a function must call itself as the last operation it
performs. You cannot use tail recursion when there is more code after the recursive call, and you
cannot use it within try/catch/ nally blocks. Currently tail recursion is only supported in the JVM
backend.
152
Higher-Order Functions and Lambdas
Kotlin functions are rst-class, which means that they can be stored in variables and data structures,
passed as arguments to and returned from other higher-order functions. You can operate with
functions in any way that is possible for other non-function values.
To facilitate this, Kotlin, as a statically typed programming language, uses a family of function types
to represent functions and provides a set of specialized language constructs, such as lambda
expressions.
Higher-Order Functions
A higher-order function is a function that takes functions as parameters, or returns a function.
A good example is the functional programming idiom fold for collections, which takes an initial
accumulator value and a combining function and builds its return value by consecutively combining
current accumulator value with each collection element, replacing the accumulator:
In the code above, the parameter combine has a function type (R, T) -> R , so it accepts a
function that takes two arguments of types R and T and returns a value of type R . It is invoked
inside the for-loop, and the return value is then assigned to accumulator .
To call fold , we need to pass it an instance of the function type as an argument, and lambda
expressions (described in more detail below) are widely used for this purpose at higher-order
function call sites:
153
val items = listOf(1, 2, 3, 4, 5)
The following sections explain in more detail the concepts mentioned so far.
Function types
Kotlin uses a family of function types like (Int) -> String for declarations that deal with
functions: val onClick: () -> Unit = ... .
These types have a special notation that corresponds to the signatures of the functions, i.e. their
parameters and return values:
— All function types have a parenthesized parameter types list and a return type: (A, B) -> C
denotes a type that represents functions taking two arguments of types A and B and returning
a value of type C . The parameter types list may be empty, as in () -> A . The Unit return
type cannot be omitted.
— Function types can optionally have an additional receiver type, which is speci ed before a dot in
the notation: the type A.(B) -> C represents functions that can be called on a receiver object
of A with a parameter of B and return a value of C . Function literals with receiver are often
used along with these types.
— Suspending functions belong to function types of a special kind, which have a suspend modi er
in the notation, such as suspend () -> Unit or suspend A.(B) -> C .
The function type notation can optionally include names for the function parameters: (x: Int,
y: Int) -> Point . These names can be used for documenting the meaning of the parameters.
To specify that a function type is nullable, use parentheses: ((Int, Int) -> Int)?.
Function types can be combined using parentheses: (Int) -> ((Int) -> Unit)
The arrow notation is right-associative, (Int) -> (Int) -> Unit is equivalent to the
previous example, but not to ((Int) -> (Int)) -> Unit.
154
You can also give a function type an alternative name by using a type alias:
Function literals with receiver can be used as values of function types with receiver.
— a constructor: ::Regex
These include bound callable references that point to a member of a particular instance:
foo::toString .
The compiler can infer the function types for variables if there is enough information:
Non-literal values of function types with and without receiver are interchangeable, so that the
receiver can stand in for the rst parameter, and vice versa. For instance, a value of type (A, B)
-> C can be passed or assigned where a A.(B) -> C is expected and the other way around:
Note that a function type with no receiver is inferred by default, even if a variable is initialized
with a reference to an extension function. To alter that, specify the variable type explicitly.
155
Invoking a function type instance
A value of a function type can be invoked by using its invoke(...) operator: f.invoke(x) or
just f(x) .
If the value has a receiver type, the receiver object should be passed as the rst argument. Another
way to invoke a value of a function type with receiver is to prepend it with the receiver object, as if
the value were an extension function: 1.foo(2) ,
Example:
println(stringPlus.invoke("<-", "->"))
println(stringPlus("Hello, ", "world!"))
println(intPlus.invoke(1, 1))
println(intPlus(1, 2))
println(2.intPlus(3)) // extension-like call
Inline functions
Sometimes it is bene cial to use inline functions, which provide exible control ow, for higher-
order functions.
Function max is a higher-order function, it takes a function value as the second argument. This
second argument is an expression that is itself a function, i.e. a function literal, which is equivalent
to the following named function:
A lambda expression is always surrounded by curly braces, parameter declarations in the full
syntactic form go inside curly braces and have optional type annotations, the body goes after an -
> sign. If the inferred return type of the lambda is not Unit , the last (or possibly single)
expression inside the lambda body is treated as the return value.
If we leave all the optional annotations out, what's left looks like this:
156
val sum: (Int, Int) -> Int = { x, y -> x + y }
In Kotlin, there is a convention that if the last parameter of a function accepts a function, a lambda
expression that is passed as the corresponding argument can be placed outside the parentheses:
If the lambda is the only argument to that call, the parentheses can be omitted entirely:
run { println("...") }
It's very common that a lambda expression has only one parameter.
If the compiler can gure the signature out itself, it is allowed not to declare the only parameter
and omit -> . The parameter will be implicitly declared under the name it :
We can explicitly return a value from the lambda using the quali ed return syntax. Otherwise, the
value of the last expression is implicitly returned.
ints.filter {
val shouldFilter = it > 0
shouldFilter
}
ints.filter {
val shouldFilter = it > 0
return@filter shouldFilter
}
This convention, along with passing a lambda expression outside parentheses, allows for LINQ-
style code:
If the lambda parameter is unused, you can place an underscore instead of its name:
157
Destructuring in lambdas (since 1.1)
Anonymous functions
One thing missing from the lambda expression syntax presented above is the ability to specify the
return type of the function. In most cases, this is unnecessary because the return type can be
inferred automatically. However, if you do need to specify it explicitly, you can use an alternative
syntax: an anonymous function.
An anonymous function looks very much like a regular function declaration, except that its name is
omitted. Its body can be either an expression (as shown above) or a block:
The parameters and the return type are speci ed in the same way as for regular functions, except
that the parameter types can be omitted if they can be inferred from context:
The return type inference for anonymous functions works just like for normal functions: the return
type is inferred automatically for anonymous functions with an expression body and has to be
speci ed explicitly (or is assumed to be Unit ) for anonymous functions with a block body.
Note that anonymous function parameters are always passed inside the parentheses. The
shorthand syntax allowing to leave the function outside the parentheses works only for lambda
expressions.
One other di erence between lambda expressions and anonymous functions is the behavior of
non-local returns. A return statement without a label always returns from the function declared
with the fun keyword. This means that a return inside a lambda expression will return from the
enclosing function, whereas a return inside an anonymous function will return from the
anonymous function itself.
Closures
A lambda expression or anonymous function (as well as a local function and an object expression)
can access its closure, i.e. the variables declared in the outer scope. Unlike Java, the variables
captured in the closure can be modi ed:
158
var sum = 0
ints.filter { it > 0 }.forEach {
sum += it
}
print(sum)
Function types with receiver, such as A.(B) -> C , can be instantiated with a special form of
function literals – function literals with receiver.
As said above, Kotlin provides the ability to call an instance of a function type with receiver
providing the receiver object.
Inside the body of the function literal, the receiver object passed to a call becomes an implicit this,
so that you can access the members of that receiver object without any additional quali ers, or
access the receiver object using a this expression.
This behavior is similar to extension functions, which also allow you to access the members of the
receiver object inside the body of the function.
Here is an example of a function literal with receiver along with its type, where plus is called on
the receiver object:
The anonymous function syntax allows you to specify the receiver type of a function literal directly.
This can be useful if you need to declare a variable of a function type with receiver, and to use it
later.
Lambda expressions can be used as function literals with receiver when the receiver type can be
inferred from context. One of the most important examples of their usage is type-safe builders:
class HTML {
fun body() { ... }
}
159
Inline Functions
Using higher-order functions imposes certain runtime penalties: each function is an object, and it
captures a closure, i.e. those variables that are accessed in the body of the function. Memory
allocations (both for function objects and classes) and virtual calls introduce runtime overhead.
But it appears that in many cases this kind of overhead can be eliminated by inlining the lambda
expressions. The functions shown below are good examples of this situation. I.e., the lock()
function could be easily inlined at call-sites. Consider the following case:
lock(l) { foo() }
Instead of creating a function object for the parameter and generating a call, the compiler could
emit the following code:
l.lock()
try {
foo()
}
finally {
l.unlock()
}
To make the compiler do this, we need to mark the lock() function with the inline modi er:
The inline modi er a ects both the function itself and the lambdas passed to it: all of those will
be inlined into the call site.
Inlining may cause the generated code to grow; however, if we do it in a reasonable way (i.e.
avoiding inlining large functions), it will pay o in performance, especially at "megamorphic" call-
sites inside loops.
noinline
In case you want only some of the lambdas passed to an inline function to be inlined, you can mark
some of your function parameters with the noinline modi er:
inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) { ... }
Inlinable lambdas can only be called inside the inline functions or passed as inlinable arguments,
but noinline ones can be manipulated in any way we like: stored in elds, passed around etc.
Note that if an inline function has no inlinable function parameters and no rei ed type parameters,
the compiler will issue a warning, since inlining such functions is very unlikely to be bene cial (you
can suppress the warning if you are sure the inlining is needed using the annotation
@Suppress("NOTHING_TO_INLINE") ).
160
Non-local returns
In Kotlin, we can only use a normal, unquali ed return to exit a named function or an
anonymous function. This means that to exit a lambda, we have to use a label, and a bare return
is forbidden inside a lambda, because a lambda cannot make the enclosing function return:
fun foo() {
ordinaryFunction {
return // ERROR: cannot make `foo` return here
}
}
But if the function the lambda is passed to is inlined, the return can be inlined as well, so it is
allowed:
fun foo() {
inlined {
return // OK: the lambda is inlined
}
}
Such returns (located in a lambda, but exiting the enclosing function) are called non-local returns.
We are used to this sort of construct in loops, which inline functions often enclose:
Note that some inline functions may call the lambdas passed to them as parameters not directly
from the function body, but from another execution context, such as a local object or a nested
function. In such cases, non-local control ow is also not allowed in the lambdas. To indicate that,
the lambda parameter needs to be marked with the crossinline modi er:
break and continue are not yet available in inlined lambdas, but we are planning to support
them too.
161
fun <T> TreeNode.findParentOfType(clazz: Class<T>): T? {
var p = parent
while (p != null && !clazz.isInstance(p)) {
p = p.parent
}
@Suppress("UNCHECKED_CAST")
return p as T?
}
Here, we walk up a tree and use re ection to check if a node has a certain type. It’s all ne, but the
call site is not very pretty:
treeNode.findParentOfType(MyTreeNode::class.java)
What we actually want is simply pass a type to this function, i.e. call it like this:
treeNode.findParentOfType<MyTreeNode>()
To enable this, inline functions support rei ed type parameters, so we can write something like this:
We quali ed the type parameter with the reified modi er, now it’s accessible inside the
function, almost as if it were a normal class. Since the function is inlined, no re ection is needed,
normal operators like !is and as are working now. Also, we can call it as mentioned above:
myTree.findParentOfType<MyTreeNodeType>() .
Though re ection may not be needed in many cases, we can still use it with a rei ed type
parameter:
Normal functions (not marked as inline) cannot have rei ed parameters. A type that does not have
a run-time representation (e.g. a non-rei ed type parameter or a ctitious type like Nothing )
cannot be used as an argument for a rei ed type parameter.
162
val foo: Foo
inline get() = Foo()
You can also annotate an entire property, which marks both of its accessors as inline:
At the call site, inline accessors are inlined as regular inline functions.
This imposes certain risks of binary incompatibility caused by changes in the module that declares
an inline function in case the calling module is not re-compiled after the change.
To eliminate the risk of such incompatibility being introduced by a change in non-public API of a
module, the public API inline functions are not allowed to use non-public-API declarations, i.e.
private and internal declarations and their parts, in their bodies.
An internal declaration can be annotated with @PublishedApi , which allows its use in public
API inline functions. When an internal inline function is marked as @PublishedApi , its body is
checked too, as if it were public.
163
Multiplatform Programming
Platform-Speci c Declarations
Multiplatform projects are an experimental feature in Kotlin 1.2 and 1.3. All of the
language and tooling features described in this document are subject to change in future
Kotlin versions.
One of the key capabilities of Kotlin's multiplatform code is a way for common code to depend on
platform-speci c declarations. In other languages, this can often be accomplished by building a set
of interfaces in the common code and implementing these interfaces in platform-speci c modules.
However, this approach is not ideal in cases when you have a library on one of the platforms that
implements the functionality you need, and you'd like to use the API of this library directly without
extra wrappers. Also, it requires common declarations to be expressed as interfaces, which doesn't
cover all possible cases.
As an alternative, Kotlin provides a mechanism of expected and actual declarations. With this
mechanism, a common module can de ne expected declarations, and a platform module can
provide actual declarations corresponding to the expected ones. To see how this works, let's look at
an example rst. This code is part of a common module:
package org.jetbrains.foo
fun main() {
Foo("Hello").frob()
}
package org.jetbrains.foo
— An expected declaration in the common module and its actual counterparts always have exactly
164
the same fully quali ed name.
— An expected declaration is marked with the expect keyword; the actual declaration is marked
with the actual keyword.
— All actual declarations that match any part of an expected declaration need to be marked as
actual .
— Expected declarations never contain any implementation code.
Note that expected declarations are not restricted to interfaces and interface members. In this
example, the expected class has a constructor and can be created directly from common code. You
can apply the expect modi er to other declarations as well, including top-level declarations and
annotations:
// Common
expect fun formatString(source: String, vararg args: Any): String
// JVM
actual fun formatString(source: String, vararg args: Any) =
String.format(source, *args)
The compiler ensures that every expected declaration has actual declarations in all platform
modules that implement the corresponding common module, and reports an error if any actual
declarations are missing. The IDE provides tools that help you create the missing actual
declarations.
If you have a platform-speci c library that you want to use in common code while providing your
own implementation for another platform, you can provide a typealias to an existing class as the
actual declaration:
165
Building Multiplatform Projects with Gradle
Multiplatform projects are an experimental feature in Kotlin 1.2 and 1.3. All of the
language and tooling features described in this document are subject to change in future
Kotlin versions.
This document describes how Kotlin multiplatform projects are con gured and built using Gradle.
Only Gradle versions 4.7 and above can be used, older Gradle versions are not supported.
Gradle Kotlin DSL support has not been implemented yet for multiplatform projects, it will be
added in the future updates. Please use the Groovy DSL in the build scripts.
For example, if you choose "Kotlin (Multiplatform Library)", a library project is created that has
three targets, one for the JVM, one for JS, and one for the Native platform that you are using. These
are con gured in the build.gradle script in the following way:
plugins {
id 'org.jetbrains.kotlin.multiplatform' version '1.3.11'
}
repositories {
mavenCentral()
}
kotlin {
targets {
fromPreset(presets.jvm, 'jvm')
fromPreset(presets.js, 'js')
fromPreset(presets.mingwX64, 'mingw')
}
sourceSets { /* ... */ }
}
The three targets are created from the presets that provide some default con guration. There are
presets for each of the supported platforms.
The source sets and their dependencies are then con gured as follows:
166
plugins { /* ... */ }
kotlin {
targets { /* ... */ }
sourceSets {
commonMain {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib-common'
}
}
commonTest {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-test-common'
implementation 'org.jetbrains.kotlin:kotlin-test-annotations-common'
}
}
jvmMain {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
}
}
jvmTest {
dependencies {
implementation 'org.jetbrains.kotlin:kotlin-test'
implementation 'org.jetbrains.kotlin:kotlin-test-junit'
}
}
jsMain { /* ... */ }
jsTest { /* ... */ }
mingwMain { /* ... */ }
mingwTest { /* ... */ }
}
}
These are the default source set names for the production and test sources for the targets
con gured above. The source sets commonMain and commonTest are included into production
and test compilations, respectively, of all targets. Note that the dependencies for common source
sets commonMain and commonTest are the common artifacts, and the platform libraries go to
the source sets of the speci c targets.
The details on project structure and the DSL can be found in the following sections.
Gradle Plugin
To setup a multiplatform project from scratch, rst, apply the kotlin-multiplatform plugin to
the project by adding the following to the build.gradle le:
plugins {
id 'org.jetbrains.kotlin.multiplatform' version '1.3.11'
}
This creates the kotlin extension at the top level. You can then access it in the build script for:
— setting up the targets for multiple platforms (no targets are created by default);
— con guring the source sets and their dependencies;
167
Setting up Targets
A target is a part of the build responsible for compiling, testing, and packaging a piece of software
aimed for one of the supported platforms.
As the platforms are di erent, targets are built in di erent ways as well and have various platform-
speci c settings. The Gradle plugin bundles a number of presets for the supported platforms. A
preset can be used to create a target by just providing a name as follows:
kotlin {
targets {
fromPreset(presets.jvm, 'jvm6') // Create a JVM target by the name 'jvm6'
fromPreset(presets.linuxX64, 'linux') {
/* You can specify additional settings for the 'linux' target here */
}
}
}
Building a target requires compiling Kotlin once or multiple times. Each Kotlin compilation of a
target may serve a di erent purpose (e.g. production code, tests) and incorporate di erent source
sets. The compilations of a target may be accessed in the DSL, for example, to get the task names,
dependency les and compilation outputs:
kotlin {
targets {
fromPreset(presets.jvm, 'jvm6') {
def mainKotlinTaskName = compilations.main.compileKotlinTaskName
def mainOutputs = compilations.main.output
def testRuntimeClasspath = compilations.test.runtimeDependencyFiles
}
}
}
To modify the Kotlin compiler options of a compilation, use the compilation's task which can be
found by its name:
168
kotlin {
targets {
fromPreset(presets.jvm, 'jvm8') {
// Configure a single target's compilations (main and test)
compilations.all {
tasks[compileKotlinTaskName].kotlinOptions {
jvmTarget = '1.8'
}
}
}
/* ... */
All of the targets may share some of the sources and may have platform-speci c sources in their
compilations as well. See Con guring source sets for details.
Some targets may require additional con guration. For Android and iOS examples, see the
Multiplatform Project: iOS and Android tutorial.
Supported platforms
There are target presets that one can apply using fromPreset(presets.<presetName>,
'<targetName>') , as described above, for the following target platforms:
— js for Kotlin/JS;
— android for Android applications and libraries. Note that one of the Android Gradle plugins
should be applied as well;
Note that some of the Kotlin/Native targets require an appropriate host machine to build on.
169
Con guring source sets
A Kotlin source set is a collection of Kotlin sources, along with their resources, dependencies, and
language settings, which may take part in Kotlin compilations of one or more targets.
If you apply a target preset, some source sets are created and con gured by default. See Default
Project Layout.
The source sets are con gured within a sourceSets { ... } block of the kotlin { ... }
extension:
kotlin {
targets { /* ... */ }
sourceSets {
foo { /* ... */ } // create or configure a source set by the name 'foo'
bar { /* ... */ }
}
}
Note: creating a source set does not link it to any target. Some source sets are prede ned
and thus compiled by default. However, custom source sets always need to be explicitly
directed to the compilations. See: Connecting source sets.
The source set names are case-sensitive. When referring to a default source set, make sure the
name pre x matches a target's name, for example, a source set iosX64Main for a target
iosX64 .
To add Kotlin source directories and resources to a source set, use its kotlin and resources
SourceDirectorySet s:
kotlin {
sourceSets {
commonMain {
kotlin.srcDir('src')
resources.srcDir('res')
}
}
}
Kotlin source sets may be connected with the 'depends on' relation, so that if a source set foo
depends on a source set bar then:
170
— whenever foo is compiled for a certain target, bar takes part in that compilation as well and
is also compiled into the same target binary form, such as JVM class les or JS code;
— the resources of bar are always processed and copied along with the resources of foo ;
— sources of foo 'see' the declarations of bar , including the internal ones, and the
dependencies of bar , even those speci ed as implementation dependencies;
— foo may contain platform-speci c implementations for the expected declarations of bar ;
The source sets DSL can be used to de ne these connections between the source sets:
kotlin {
sourceSets {
commonMain { /* ... */ }
allJvm {
dependsOn commonMain
/* ... */
}
}
}
Custom source sets created in addition to the default ones should be explicitly included into the
dependencies hierarchy to be able to use declarations from other source sets and, most
importantly, to take part in compilations. Most often, they need a dependsOn commonMain or
dependsOn commonTest statement, and some of the default platform-speci c source sets
should depend on the custom ones, directly or indirectly:
kotlin {
targets {
fromPreset(presets.mingwX64, 'windows')
fromPreset(presets.linuxX64, 'linux')
/* ... */
}
sourceSets {
desktopTest { // custom source set with tests for the two targets
dependsOn commonTest
/* ... */
}
windowsTest { // default test source set for target 'windows'
dependsOn desktopTest
/* ... */
}
linuxTest { // default test source set for target 'linux'
dependsOn desktopTest
}
/* ... */
}
}
Adding Dependencies
171
To add a dependency to a source set, use a dependencies { ... } block of the source sets
DSL. Four kinds of dependencies are supported:
— api dependencies are used both during compilation and at runtime and are exported to
library consumers. If any types from a dependency are used in the public API of the current
module, then it should be an api dependency;
— implementation dependencies are used during compilation and at runtime for the current
module, but are not exposed for compilation of other modules depending on the one with the
implementation dependency. The implementation dependency kind should be used for
dependencies needed for the internal logic of a module. If a module is an endpoint application
which is not published, it may use implementation dependencies instead of api ones.
— compileOnly dependencies are only used for compilation of the current module and are
available neither at runtime nor during compilation of other modules. These dependencies
should be used for APIs which have a third-party implementation available at runtime.
— runtimeOnly dependencies are available at runtime but are not visible during compilation of
any module.
kotlin {
sourceSets {
commonMain {
dependencies {
api 'com.example:foo-metadata:1.0'
}
}
jvm6Main {
dependencies {
api 'com.example:foo-jvm6:1.0'
}
}
}
}
Note that for the IDE to correctly analyze the dependencies of the common sources, the common
source sets need to have corresponding dependencies on the Kotlin metadata packages in addition
to the platform-speci c artifact dependencies of the platform-speci c source sets. Usually, an
artifact with a su x -common (as in kotlin-stdlib-common ) or -metadata is required when
using a published library (unless it is published with Gradle metadata, as described below).
172
Likewise, if a multiplatform library is published in the experimental Gradle metadata publishing
mode and the project is set up to consume the metadata as well, then it is enough to specify a
dependency only once, for the common source set. Otherwise, each platform-speci c source set
should be provided with a corresponding platform module of the library, in addition to the
common module, as shown above.
An alternative way to specify the dependencies is to use the Gradle built-in DSL at the top level with
the con guration names following the pattern <sourceSetName><DependencyKind> :
dependencies {
commonMainApi 'com.example:foo-common:1.0'
jvm6MainApi 'com.example:foo-jvm6:1.0'
}
Language settings
kotlin {
sourceSets {
commonMain {
languageSettings {
languageVersion = '1.3' // possible values: '1.0', '1.1', '1.2', '1.3'
apiVersion = '1.3' // possible values: '1.0', '1.1', '1.2', '1.3'
enableLanguageFeature('InlineClasses') // language feature name
useExperimentalAnnotation('kotlin.ExperimentalUnsignedTypes') // annotation
FQ-name
progressiveMode = true // false by default
}
}
}
}
It is possible to con gure the language settings of all source sets at once:
kotlin.sourceSets.all {
languageSettings {
progressiveMode = true
}
}
Language settings of a source set a ect how the sources are analyzed in the IDE. Due to the current
limitations, in a Gradle build, only the language settings of the compilation's default source set are
used.
The language settings are checked for consistency between source sets depending on each other.
Namely, if foo depends on bar :
— foo should set languageVersion that is greater than or equal to that of bar ;
— foo should enable all unstable language features that bar enables (there's no such
requirement for bug x features);
— foo should use all experimental annotations that bar uses;
173
— apiVersion , bug x language features, and progressiveMode can be set arbitrarily;
Then, once a target is added, default compilations are created for it:
— main and test compilations for JVM, JS, and Native targets;
For each compilation, there is a default source set under the name composed as <targetName>
<CompilationName> . This default source set participates in the compilation, and thus it should
be used for the platform-speci c code and dependencies, and for adding other source sets to the
compilation by the means of 'depends on'. For example, a project with targets jvm6 (JVM) and
nodeJs (JS) will have source sets: commonMain , commonTest , jvm6Main , jvm6Test ,
nodeJsMain , nodeJsTest .
Numerous use cases are covered by just the default source sets and don't require custom source
sets.
Each source set by default has its Kotlin sources under src/<sourceSetName>/kotlin
directory and the resources under src/<sourceSetName>/resources .
In Android projects, additional Kotlin source sets are created for each Android source set. If the
Android target has a name foo , the Android source set bar gets a Kotlin source set counterpart
fooBar . The Kotlin compilations, however, are able to consume Kotlin sources from all of the
directories src/bar/java , src/bar/kotlin , and src/fooBar/kotlin . Java sources are only
read from the rst of these directories.
Running Tests
Running tests in a Gradle build is currently supported by default for JVM, Android, Linux, Windows
and macOS; JS and other Kotlin/Native targets need to be manually con gured to run the tests with
an appropriate environment, an emulator or a test framework.
A test task is created under the name <targetName>Test for each target that is suitable for
testing. Run the check task to run the tests for all targets.
As the commonTest default source set is added to all test compilations, tests and test tools that
are needed on all target platforms may be placed there.
174
The kotlin.test API is availble for multiplatform tests. Add the kotlin-test-common and
kotlin-test-annotations-common dependencies to commonTest to use
DefaultAsserter and @Test / @Ignore / @BeforeTest / @AfterTest annotations in the
common tests.
For Kotlin/JS targets, add kotlin-test-js as a test dependency. At this point, test tasks for
Kotlin/JS are created but do not run tests by default; they should be manually con gured to run the
tests with a JavaScript test framework.
Kotlin/Native targets do not require additional test dependencies, and the kotlin.test API
implementations are built-in.
The set of target platforms is de ned by a multiplatform library author, and they should
provide all of the platform-speci c implementations for the library. Adding new targets for
a multiplatform library at the consumer's side is not supported.
A library built from a multiplatform project may be published to a Maven repository with the
Gradle maven-publish plugin, which can be applied as follows:
plugins {
/* ... */
id 'maven-publish'
}
Once this plugin is applied, default publications are created for each of the targets that can be built
on the current host. This requires group and version to be set in the project. The default
artifact IDs follow the pattern <projectName>-<targetNameToLowerCase> , for example
sample-lib-nodejs for a target named nodeJs in a project sample-lib .
Also, an additional publication is added by default which contains serialized Kotlin declarations and
is used by the IDE to analyze multiplatform libraries.
By default, a sources JAR is added to each publication in addition to its main artifact. The sources
JAR contains the sources used by the main compilation of the target.
The Maven coordinates can be altered and additional artifact les may be added to the publication
within the targets { ... } block:
175
kotlin {
targets {
fromPreset(presets.jvm, 'jvm6') {
/* ... */
mavenPublication {
artifactId = 'sample-lib-jvm'
artifact(jvmJavadocJar)
}
}
}
}
If a library is published with Gradle metadata enabled and a consumer enables the metadata as
well, the consumer may specify a single dependency on the library in a common source set, and a
corresponding platform-speci c variant will be chosen, if available, for each of the compilations.
Consider a sample-lib library built for the JVM and JS and published with experimental Gradle
metadata. Then it is enough for the consumers to add
enableFeaturePreview('GRADLE_METADATA) and specify a single dependency:
kotlin {
targets {
fromPreset(presets.jvm, 'jvm6')
fromPreset(presets.js, 'nodeJs')
}
sourceSets {
commonMain {
dependencies {
api 'com.example:sample-lib:1.0'
// is resolved to `sample-lib-jvm` for JVM, `sample-lib-js` for JS
}
}
}
}
Disambiguating Targets
176
It is possible to have more than one target for a single platform in a multiplatform library. For
example, these targets may provide the same API and di er in the libraries they cooperate with at
runtime, like testing frameworks or logging solutions.
However, dependencies on such a multiplatform library may be ambiguous and may thus fail to
resolve under certain conditions:
— In both of the cases above, another solution is to mark the targets with a custom attribute. This,
however, must be done on both the library author and the consumer sides, and it's the library
author's responsibility to communicate the attribute and its values to the consumers;
Add the following symmetrically, to both the library and the consumer projects. The consumer
may only need to mark a single target with the attribute:
def testFrameworkAttribute =
Attribute.of('com.example.testFramework', String)
kotlin {
targets {
fromPreset(presets.jvm, 'junit') {
attributes.attribute(testingFrameworkAttribute, 'junit')
}
fromPreset(presets.jvm, 'testng') {
attributes.attribute(testingFrameworkAttribute,
'testng')
}
}
}
177
A target that is not supported by the current host is ignored during build and therefore not
published. A library author may want to set up builds and publishing from di erent hosts as
required by the library target platforms.
By default, a Kotlin/Native target is compiled down to a *.klib library artifact, which can be
consumed by Kotlin/Native itself as a dependency but cannot be run or used as a native library.
To link a binary in addition to the Kotlin/Native library, add one or more of the outputKinds ,
which can be:
— framework for an Objective-C framework (only supported for macOS and iOS targets)
kotlin {
targets {
fromPreset(presets.linuxX64, 'linux') {
compilations.main.outputKinds 'executable' // could be 'static', 'dynamic'
}
}
}
This creates additional link tasks for the debug and release binaries. The tasks can be accessed
after project evaluation from the compilation as, for example, getLinkTask('executable',
'release') or getLinkTaskName('static', 'debug') . To get the binary le, use
getBinary , for example, as getBinary('executable', 'release') or
getBinary('static', 'debug') .
CInterop support
Since Kotlin/Native provides interoperability with native languages, there is a DSL allowing one to
con gure this feature for a speci c compilation.
A compilation can interact with several native libraries. Interoperability with each of them can be
con gured in the cinterops block of the compilation:
178
// In the scope of a Kotlin/Native target's compilation:
cinterops {
myInterop {
// Def-file describing the native API.
// The default path is src/nativeInterop/cinterop/<interop-name>.def
defFile project.file("def-file.def")
anotherInterop { /* ... */ }
}
Often it's necessary to specify target-speci c linker options for a binary which uses a native library.
It can be done using the linkerOpts DSL method of a Kotlin/Native compilation:
compilations.main {
linkerOpts '-L/lib/search/path -L/another/search/path -lmylib'
}
179
Other
Destructuring Declarations
Sometimes it is convenient to destructure an object into a number of variables, for example:
println(name)
println(age)
The component1() and component2() functions are another example of the principle of
conventions widely used in Kotlin (see operators like + and * , for-loops etc.). Anything can be on
the right-hand side of a destructuring declaration, as long as the required number of component
functions can be called on it. And, of course, there can be component3() and component4()
and so on.
Note that the componentN() functions need to be marked with the operator keyword to allow
using them in a destructuring declaration.
Variables a and b get the values returned by component1() and component2() called on
elements of the collection.
180
data class Result(val result: Int, val status: Status)
fun function(...): Result {
// computations
NOTE: we could also use the standard class Pair and have function() return Pair<Int,
Status> , but it's often better to have your data named properly.
So you can freely use destructuring declarations in for-loops with maps (as well as collections of
data class instances etc).
The componentN() operator functions are not called for the components that are skipped in this
way.
181
You can use the destructuring declarations syntax for lambda parameters. If a lambda has a
parameter of the Pair type (or Map.Entry , or any other type that has the appropriate
componentN functions), you can introduce several new parameters instead of one by putting
them in parentheses:
Note the di erence between declaring two parameters and declaring a destructuring pair instead
of a parameter:
If a component of the destructured parameter is unused, you can replace it with the underscore to
avoid inventing its name:
You can specify the type for the whole destructured parameter or for a speci c component
separately:
182
Collections: List, Set, Map
Unlike many languages, Kotlin distinguishes between mutable and immutable collections (lists, sets,
maps, etc). Precise control over exactly when collections can be edited is useful for eliminating
bugs, and for designing good APIs.
The Kotlin List<out T> type is an interface that provides read-only operations like size , get
and so on. Like in Java, it inherits from Collection<T> and that in turn inherits from
Iterable<T> . Methods that change the list are added by the MutableList<T> interface. This
pattern holds also for Set<out T>/MutableSet<T> and Map<K, out V>/MutableMap<K,
V> .
We can see basic usage of the list and set types below:
Kotlin does not have dedicated syntax constructs for creating lists or sets. Use methods from the
standard library, such as listOf() , mutableListOf() , setOf() , mutableSetOf() . Map
creation in NOT performance-critical code can be accomplished with a simple idiom: mapOf(a to
b, c to d) .
Note that the readOnlyView variable points to the same list and changes as the underlying list
changes. If the only references that exist to a list are of the read-only variety, we can consider the
collection fully immutable. A simple way to create such a collection is like this:
Currently, the listOf method is implemented using an array list, but in future more memory-
e cient fully immutable collection types could be returned that exploit the fact that they know
they can't change.
Note that the read-only types are covariant. That means, you can take a List<Rectangle> and
assign it to List<Shape> assuming Rectangle inherits from Shape (the collection types have
the same inheritance relationship as the element types). This wouldn't be allowed with the mutable
collection types because it would allow for failures at runtime: you might add a Circle into the
List<Shape> , creating a List<Rectangle> with a Circle in it somewhere else in the
program.
183
Sometimes you want to return to the caller a snapshot of a collection at a particular point in time,
one that's guaranteed to not change:
class Controller {
private val _items = mutableListOf<String>()
val items: List<String> get() = _items.toList()
}
The toList extension method just duplicates the lists items, thus, the returned list is guaranteed
to never change.
There are various useful extension methods on lists and sets that are worth being familiar with:
… as well as all the utilities you would expect such as sort, zip, fold, reduce and so on.
It's important to note, that the operations on readonly collections which return a modi ed
collection (like + , filter , drop , etc.) do not create their results atomically, therefore the results
are not safe to use from a di erent thread without proper synchronization.
Maps follow the same pattern. They can be easily instantiated and accessed like this:
184
Ranges
Range expressions are formed with rangeTo functions that have the operator form .. which is
complemented by in and !in. Range is de ned for any comparable type, but for integral primitive
types it has an optimized implementation. Here are some examples of using ranges:
Integral type ranges ( IntRange , LongRange , CharRange ) have an extra feature: they can be
iterated over. The compiler takes care of converting this analogously to Java's indexed for-loop,
without extra overhead:
What if you want to iterate over numbers in reverse order? It's simple. You can use the downTo()
function de ned in the standard library:
Is it possible to iterate over numbers with arbitrary step, not equal to 1? Sure, the step()
function will help you:
To create a range which does not include its end element, you can use the until function:
How it works
Ranges implement a common interface in the library: ClosedRange<T> .
ClosedRange<T> denotes a closed interval in the mathematical sense, de ned for comparable
types. It has two endpoints: start and endInclusive , which are included in the range. The
main operation is contains , usually used in the form of in/!in operators.
185
A progression is a subtype of Iterable<N> , where N is Int , Long or Char respectively, so it
can be used in for-loops and functions like map , filter , etc. Iteration over Progression is
equivalent to an indexed for-loop in Java/JavaScript:
For integral types, the .. operator creates an object which implements both ClosedRange<T>
and *Progression . For example, IntRange implements ClosedRange<Int> and extends
IntProgression , thus all operations de ned for IntProgression are available for
IntRange as well. The result of the downTo() and step() functions is always a
*Progression .
Progressions are constructed with the fromClosedRange function de ned in their companion
objects:
The last element of the progression is calculated to nd maximum value not greater than the
end value for positive step or minimum value not less than the end value for negative step
such that (last - first) % step == 0 .
Utility functions
rangeTo()
The rangeTo() operators on integral types simply call the constructors of *Range classes, e.g.:
class Int {
//...
operator fun rangeTo(other: Long): LongRange = LongRange(this, other)
//...
operator fun rangeTo(other: Int): IntRange = IntRange(this, other)
//...
}
Floating point numbers ( Double , Float ) do not de ne their rangeTo operator, and the one
provided by the standard library for generic Comparable types is used instead:
downTo()
The downTo() extension function is de ned for any pair of integral types, here are two examples:
186
fun Long.downTo(other: Int): LongProgression {
return LongProgression.fromClosedRange(this, other.toLong(), -1L)
}
reversed()
The reversed() extension functions are de ned for each *Progression classes, and all of
them return reversed progressions:
step()
step() extension functions are de ned for *Progression classes, all of them return
progressions with modi ed step values (function parameter). The step value is required to be
always positive, therefore this function never changes the direction of iteration:
Note that the last value of the returned progression may become di erent from the last
value of the original progression in order to preserve the invariant (last - first) % step ==
0 . Here is an example:
187
Type Checks and Casts: 'is' and 'as'
if (obj is String) {
print(obj.length)
}
Smart Casts
In many cases, one does not need to use explicit cast operators in Kotlin, because the compiler
tracks the is -checks and explicit casts for immutable values and inserts (safe) casts automatically
when needed:
The compiler is smart enough to know a cast to be safe if a negative check leads to a return:
when (x) {
is Int -> print(x + 1)
is String -> print(x.length + 1)
is IntArray -> print(x.sum())
}
188
Note that smart casts do not work when the compiler cannot guarantee that the variable cannot
change between the check and the usage. More speci cally, smart casts are applicable according to
the following rules:
— val properties - if the property is private or internal or the check is performed in the same
module where the property is declared. Smart casts aren't applicable to open properties or
properties that have custom getters;
— var local variables - if the variable is not modi ed between the check and the usage, is not
captured in a lambda that modi es it, and is not a local delegated property;
— var properties - never (because the variable can be modi ed at any time by other code).
Note that null cannot be cast to String as this type is not nullable, i.e. if y is null, the code
above throws an exception. In order to match Java cast semantics we have to have nullable type at
cast right hand side, like:
Note that despite the fact that the right-hand side of as? is a non-null type String the result of
the cast is nullable.
Given that, the compiler prohibits is-checks that cannot be performed at runtime due to type
erasure, such as ints is List<Int> or list is T (type parameter). You can, however, check
an instance against a star-projected type:
189
if (something is List<*>) {
something.forEach { println(it) } // The items are typed as `Any?`
}
Similarly, when you already have the type arguments of an instance checked statically (at compile
time), you can make an is-check or a cast that involves the non-generic part of the type. Note that
angle brackets are omitted in this case:
The same syntax with omitted type arguments can be used for casts that do not take type
arguments into account: list as ArrayList .
Inline functions with rei ed type parameters have their actual type arguments inlined at each call
site, which enables arg is T checks for the type parameters, but if arg is an instance of a
generic type itself, its type arguments are still erased. Example:
Unchecked casts
As said above, type erasure makes checking actual type arguments of a generic type instance
impossible at runtime, and generic types in the code might be connected to each other not closely
enough for the compiler to ensure type safety.
Even so, sometimes we have high-level program logic that implies type safety instead. For example:
The compiler produces a warning for the cast in the last line. The cast cannot be fully checked at
runtime and provides no guarantee that the values in the map are Int .
190
To avoid unchecked casts, you can redesign the program structure: in the example above, there
could be interfaces DictionaryReader<T> and DictionaryWriter<T> with type-safe
implementations for di erent types. You can introduce reasonable abstractions to move
unchecked casts from calling code to the implementation details. Proper use of generic variance
can also help.
For generic functions, using rei ed type parameters makes the casts such as arg as T checked,
unless arg 's type has its own type arguments that are erased.
An unchecked cast warning can be suppressed by annotating the statement or the declaration
where it occurs with @Suppress("UNCHECKED_CAST") :
On the JVM, the array types ( Array<Foo> ) retain the information about the erased type of their
elements, and the type casts to an array type are partially checked: the nullability and actual type
arguments of the elements type are still erased. For example, the cast foo as
Array<List<String>?> will succeed if foo is an array holding any List<*> , nullable or not.
191
This Expression
To denote the current receiver, we use this expressions:
— In an extension function or a function literal with receiver this denotes the receiver parameter
that is passed on the left-hand side of a dot.
If this has no quali ers, it refers to the innermost enclosing scope. To refer to this in other scopes,
label quali ers are used:
Quali ed this
To access this from an outer scope (a class, or extension function, or labeled function literal with
receiver) we write this@label where @label is a label on the scope this is meant to be from:
192
Equality
In Kotlin there are two types of equality:
Structural equality
Structural equality is checked by the == operation (and its negated counterpart != ). By
convention, an expression like a == b is translated to:
I.e. if a is not null , it calls the equals(Any?) function, otherwise (i.e. a is null ) it checks that
b is referentially equal to null .
Note that there's no point in optimizing your code when comparing to null explicitly: a ==
null will be automatically translated to a === null .
Otherwise, the structural equality is used, which disagrees with the standard so that NaN is equal
to itself, and -0.0 is not equal to 0.0 .
Referential equality
Referential equality is checked by the === operation (and its negated counterpart !== ). a ===
b evaluates to true if and only if a and b point to the same object. For values which are
represented as primitive types at runtime (for example, Int ), the === equality check is
equivalent to the == check.
193
Operator overloading
Kotlin allows us to provide implementations for a prede ned set of operators on our types. These
operators have xed symbolic representation (like + or * ) and xed precedence. To implement
an operator, we provide a member function or an extension function with a xed name, for the
corresponding type, i.e. left-hand side type for binary operations and argument type for unary
ones. Functions that overload operators need to be marked with the operator modi er.
Further we describe the conventions that regulate operator overloading for di erent operators.
Unary operations
This table says that when the compiler processes, for example, an expression +a , it performs the
following steps:
— Looks up a function unaryPlus() with the operator modi er and no parameters for the
receiver T , i.e. a member function or an extension function;
— If the function is absent or ambiguous, it is a compilation error;
— If the function is present and its return type is R , the expression +a has type R ;
Note that these operations, as well as all the others, are optimized for Basic types and do not
introduce overhead of function calls for them.
As an example, here's how you can overload the unary minus operator:
fun main() {
println(-point) // prints "Point(x=-10, y=-20)"
}
194
The inc() and dec() functions must return a value, which will be assigned to the variable on
which the ++ or -- operation was used. They shouldn't mutate the object on which the inc or
dec was invoked.
The compiler performs the following steps for resolution of an operator in the post x form, e.g.
a++ :
— Looks up a function inc() with the operator modi er and no parameters, applicable to the
receiver of type T ;
For the pre x forms ++a and --a resolution works the same way, and the e ect is:
Binary operations
Arithmetic operators
Expression Translated to
a + b a.plus(b)
a - b a.minus(b)
a * b a.times(b)
a / b a.div(b)
a % b a.rem(b), a.mod(b) (deprecated)
a..b a.rangeTo(b)
For the operations in this table, the compiler just resolves the expression in the Translated to
column.
Note that the rem operator is supported since Kotlin 1.1. Kotlin 1.0 uses the mod operator, which
is deprecated in Kotlin 1.1.
Example
195
Below is an example Counter class that starts at a given value and can be incremented using the
overloaded + operator:
'In' operator
Expression Translated to
a in b b.contains(a)
a !in b !b.contains(a)
For in and !in the procedure is the same, but the order of arguments is reversed.
Square brackets are translated to calls to get and set with appropriate numbers of arguments.
Invoke operator
Expression Translated to
a() a.invoke()
a(i) a.invoke(i)
a(i, j) a.invoke(i, j)
a(i_1, ..., i_n) a.invoke(i_1, ..., i_n)
Augmented assignments
Expression Translated to
a += b a.plusAssign(b)
a -= b a.minusAssign(b)
a *= b a.timesAssign(b)
a /= b a.divAssign(b)
a %= b a.remAssign(b), a.modAssign(b) (deprecated)
196
For the assignment operations, e.g. a += b , the compiler performs the following steps:
— Otherwise, try to generate code for a = a + b (this includes a type check: the type of a + b
must be a subtype of a ).
These operators only work with the function equals(other: Any?): Boolean, which can be
overridden to provide custom equality check implementation. Any other function with the same
name (like equals(other: Foo) ) will not be called.
Note: === and !== (identity checks) are not overloadable, so no conventions exist for them.
The == operation is special: it is translated to a complex expression that screens for null 's.
null == null is always true, and x == null for a non-null x is always false and won't invoke
x.equals() .
Comparison operators
Expression Translated to
a > b a.compareTo(b) > 0
a < b a.compareTo(b) < 0
a >= b a.compareTo(b) >= 0
a <= b a.compareTo(b) <= 0
All comparisons are translated into calls to compareTo , that is required to return Int .
197
We can simulate custom in x operations by using in x function calls.
198
Null Safety
One of the most common pitfalls in many programming languages, including Java, is that accessing
a member of a null reference will result in a null reference exception. In Java this would be the
equivalent of a NullPointerException or NPE for short.
Kotlin's type system is aimed to eliminate NullPointerException 's from our code. The only
possible causes of NPE's may be:
— Java interoperation:
— Attempts to access a member on a null reference of a platform type;
— Generic types used for Java interoperation with incorrect nullability, e.g. a piece of Java code
might add null into a Kotlin MutableList<String> , meaning that
MutableList<String?> should be used for working with it;
— Other issues caused by external Java code.
In Kotlin, the type system distinguishes between references that can hold null (nullable
references) and those that can not (non-null references). For example, a regular variable of type
String can not hold null:
Now, if you call a method or access a property on a , it's guaranteed not to cause an NPE, so you
can safely say:
val l = a.length
199
But if you want to access the same property on b , that would not be safe, and the compiler reports
an error:
But we still need to access that property, right? There are a few ways of doing that.
The compiler tracks the information about the check you performed, and allows the call to
length inside the if. More complex conditions are supported as well:
val b = "Kotlin"
if (b != null && b.length > 0) {
print("String of length ${b.length}")
} else {
print("Empty string")
}
Note that this only works where b is immutable (i.e. a local variable which is not modi ed between
the check and the usage or a member val which has a backing eld and is not overridable),
because otherwise it might happen that b changes to null after the check.
Safe Calls
Your second option is the safe call operator, written ?. :
val a = "Kotlin"
val b: String? = null
println(b?.length)
println(a?.length)
This returns b.length if b is not null, and null otherwise. The type of this expression is Int? .
Safe calls are useful in chains. For example, if Bob, an Employee, may be assigned to a Department
(or not), that in turn may have another Employee as a department head, then to obtain the name of
Bob's department head (if any), we write the following:
bob?.department?.head?.name
To perform a certain operation only for non-null values, you can use the safe call operator together
with let:
200
val listWithNulls: List<String?> = listOf("Kotlin", null)
for (item in listWithNulls) {
item?.let { println(it) } // prints A and ignores null
}
A safe call can also be placed on the left side of an assignment. Then, if one of the receivers in the
safe calls chain is null, the assignment is skipped, and the expression on the right is not evaluated
at all:
Elvis Operator
When we have a nullable reference r , we can say "if r is not null, use it, otherwise use some non-
null value x ":
Along with the complete if-expression, this can be expressed with the Elvis operator, written ?: :
val l = b?.length ?: -1
If the expression to the left of ?: is not null, the elvis operator returns it, otherwise it returns the
expression to the right. Note that the right-hand side expression is evaluated only if the left-hand
side is null.
Note that, since throw and return are expressions in Kotlin, they can also be used on the right
hand side of the elvis operator. This can be very handy, for example, for checking function
arguments:
The !! Operator
The third option is for NPE-lovers: the not-null assertion operator ( !! ) converts any value to a
non-null type and throws an exception if the value is null. We can write b!! , and this will return a
non-null value of b (e.g., a String in our example) or throw an NPE if b is null:
val l = b!!.length
Thus, if you want an NPE, you can have it, but you have to ask for it explicitly, and it does not
appear out of the blue.
Safe Casts
201
Regular casts may result into a ClassCastException if the object is not of the target type.
Another option is to use safe casts that return null if the attempt was not successful:
202
Exceptions
Exception Classes
All exception classes in Kotlin are descendants of the class Throwable . Every exception has a
message, stack trace and an optional cause.
try {
// some code
}
catch (e: SomeException) {
// handler
}
finally {
// optional finally block
}
There may be zero or more catch blocks. finally blocks may be omitted. However at least one
catch or finally block should be present.
Try is an expression
The returned value of a try-expression is either the last expression in the try block or the last
expression in the catch block (or blocks). Contents of the finally block do not a ect the result
of the expression.
Checked Exceptions
Kotlin does not have checked exceptions. There are many reasons for this, but we will provide a
simple example.
What does this signature say? It says that every time I append a string to something (a
StringBuilder , some kind of a log, a console, etc.) I have to catch those IOExceptions . Why?
Because it might be performing IO ( Writer also implements Appendable )… So it results into
this kind of code all over the place:
203
try {
log.append(message)
}
catch (IOException e) {
// Must be safe
}
And this is no good, see E ective Java, 3rd Edition, Item 77: Don't ignore exceptions.
Examination of small programs leads to the conclusion that requiring exception speci cations
could both enhance developer productivity and enhance code quality, but experience with
large software projects suggests a di erent result – decreased productivity and little or no
increase in code quality.
The type of the throw expression is the special type Nothing . The type has no values and is
used to mark code locations that can never be reached. In your own code, you can use Nothing
to mark a function that never returns:
When you call this function, the compiler will know that the execution doesn't continue beyond the
call:
Another case where you may encounter this type is type inference. The nullable variant of this type,
Nothing? , has exactly one possible value, which is null . If you use null to initialize a value of
an inferred type and there's no other information that can be used to determine a more speci c
type, the compiler will infer the Nothing? type:
Java Interoperability
204
Please see the section on exceptions in the Java Interoperability section for information about Java
interoperability.
205
Annotations
Annotation Declaration
Annotations are means of attaching metadata to code. To declare an annotation, put the
annotation modi er in front of a class:
Additional attributes of the annotation can be speci ed by annotating the annotation class with
meta-annotations:
— @Target speci es the possible kinds of elements which can be annotated with the annotation
(classes, functions, properties, expressions etc.);
— @Retention speci es whether the annotation is stored in the compiled class les and whether
it's visible through re ection at runtime (by default, both are true);
— @Repeatable allows using the same annotation on a single element multiple times;
— @MustBeDocumented speci es that the annotation is part of the public API and should be
included in the class or method signature shown in the generated API documentation.
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION,
AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION)
@Retention(AnnotationRetention.SOURCE)
@MustBeDocumented
annotation class Fancy
Usage
If you need to annotate the primary constructor of a class, you need to add the constructor
keyword to the constructor declaration, and add the annotations before it:
class Foo {
var x: MyDependency? = null
@Inject set
}
Constructors
206
annotation class Special(val why: String)
— enums;
— other annotations;
— arrays of the types listed above.
Annotation parameters cannot have nullable types, because the JVM does not support storing
null as a value of an annotation attribute.
If an annotation is used as a parameter of another annotation, its name is not pre xed with the @
character:
If you need to specify a class as an argument of an annotation, use a Kotlin class (KClass). The Kotlin
compiler will automatically convert it to a Java class, so that the Java code will be able to see the
annotations and arguments normally.
import kotlin.reflect.KClass
Lambdas
Annotations can also be used on lambdas. They will be applied to the invoke() method into
which the body of the lambda is generated. This is useful for frameworks like Quasar, which uses
annotations for concurrency control.
207
When you're annotating a property or a primary constructor parameter, there are multiple Java
elements which are generated from the corresponding Kotlin element, and therefore multiple
possible locations for the annotation in the generated Java bytecode. To specify how exactly the
annotation should be generated, use the following syntax:
The same syntax can be used to annotate the entire le. To do this, put an annotation with the
target file at the top level of a le, before the package directive or before all imports if the le is
in the default package:
@file:JvmName("Foo")
package org.jetbrains.demo
If you have multiple annotations with the same target, you can avoid repeating the target by adding
brackets after the target and putting all the annotations inside the brackets:
class Example {
@set:[Inject VisibleForTesting]
var collaborator: Collaborator
}
— file ;
— field ;
— delegate (the eld storing the delegate instance for a delegated property).
To annotate the receiver parameter of an extension function, use the following syntax:
If you don't specify a use-site target, the target is chosen according to the @Target annotation of
the annotation being used. If there are multiple applicable targets, the rst applicable target from
the following list is used:
— param ;
— property ;
208
— field .
Java Annotations
Java annotations are 100% compatible with Kotlin:
import org.junit.Test
import org.junit.Assert.*
import org.junit.Rule
import org.junit.rules.*
class Tests {
// apply @Rule annotation to property getter
@get:Rule val tempFolder = TemporaryFolder()
Since the order of parameters for an annotation written in Java is not de ned, you can't use a
regular function call syntax for passing the arguments. Instead, you need to use the named
argument syntax:
// Java
public @interface Ann {
int intValue();
String stringValue();
}
// Kotlin
@Ann(intValue = 1, stringValue = "abc") class C
Just like in Java, a special case is the value parameter; its value can be speci ed without an
explicit name:
// Java
public @interface AnnWithValue {
String value();
}
// Kotlin
@AnnWithValue("abc") class C
If the value argument in Java has an array type, it becomes a vararg parameter in Kotlin:
// Java
public @interface AnnWithArrayValue {
String[] value();
}
209
// Kotlin
@AnnWithArrayValue("abc", "foo", "bar") class C
For other arguments that have an array type, you need to use the array literal syntax (since Kotlin
1.2) or arrayOf(...) :
// Java
public @interface AnnWithArrayMethod {
String[] names();
}
// Kotlin 1.2+:
@AnnWithArrayMethod(names = ["abc", "foo", "bar"])
class C
// Java
public @interface Ann {
int value();
}
// Kotlin
fun foo(ann: Ann) {
val i = ann.value
}
210
Re ection
Re ection is a set of language and library features that allows for introspecting the structure of
your own program at runtime. Kotlin makes functions and properties rst-class citizens in the
language, and introspecting them (i.e. learning a name or a type of a property or function at
runtime) is closely intertwined with simply using a functional or reactive style.
On the Java platform, the runtime component required for using the re ection features is
distributed as a separate JAR le (kotlin-reflect.jar). This is done to reduce the
required size of the runtime library for applications that do not use re ection features. If
you do use re ection, please make sure that the .jar le is added to the classpath of your
project.
Class References
The most basic re ection feature is getting the runtime reference to a Kotlin class. To obtain the
reference to a statically known Kotlin class, you can use the class literal syntax:
val c = MyClass::class
Note that a Kotlin class reference is not the same as a Java class reference. To obtain a Java class
reference, use the .java property on a KClass instance.
You obtain the reference to an exact class of an object, for instance GoodWidget or BadWidget ,
despite the type of the receiver expression ( Widget ).
Callable references
References to functions, properties, and constructors, apart from introspecting the program
structure, can also be called or used as instances of function types.
The common supertype for all callable references is KCallable<out R>, where R is the return
value type, which is the property type for properties, and the constructed type for constructors.
Function References
211
fun isOdd(x: Int) = x % 2 != 0
We can easily call it directly ( isOdd(5) ), but we can also use it as a function type value, e.g. pass it
to another function. To do this, we use the :: operator:
Function references belong to one of the KFunction<out R> subtypes, depending on the
parameter count, e.g. KFunction3<T1, T2, T3, R> .
:: can be used with overloaded functions when the expected type is known from the context. For
example:
Alternatively, you can provide the necessary context by storing the method reference in a variable
with an explicitly speci ed type:
If we need to use a member of a class, or an extension function, it needs to be quali ed, e.g.
String::toCharArray .
Note that even if you initialize a variable with a reference to an extension function, the inferred
function type will have no receiver (it will have an additional parameter accepting a receiver
object). To have a function type with receiver instead, specify the type explicitly:
fun <A, B, C> compose(f: (B) -> C, g: (A) -> B): (A) -> C {
return { x -> f(g(x)) }
}
It returns a composition of two functions passed to it: compose(f, g) = f(g(*)) . Now, you
can apply it to callable references:
212
fun length(s: String) = s.length
println(strings.filter(oddLength))
Property References
To access properties as rst-class objects in Kotlin, we can also use the :: operator:
val x = 1
fun main() {
println(::x.get())
println(::x.name)
}
The expression ::x evaluates to a property object of type KProperty<Int> , which allows us to
read its value using get() or retrieve the property name using the name property. For more
information, please refer to the docs on the KProperty class.
For a mutable property, e.g. var y = 1 , ::y returns a value of type KMutableProperty<Int>,
which has a set() method:
var y = 1
fun main() {
::y.set(2)
println(y)
}
A property reference can be used where a function with one parameter is expected:
fun main() {
println(String::lastChar.get("abc"))
}
213
On the Java platform, standard library contains extensions for re ection classes that provide a
mapping to and from Java re ection objects (see package kotlin.reflect.jvm ). For example,
to nd a backing eld or a Java method that serves as a getter for a Kotlin property, you can say
something like this:
import kotlin.reflect.jvm.*
fun main() {
println(A::p.javaGetter) // prints "public final int A.getP()"
println(A::p.javaField) // prints "private final int A.p"
}
To get the Kotlin class corresponding to a Java class, use the .kotlin extension property:
Constructor References
Constructors can be referenced just like methods and properties. They can be used wherever an
object of function type is expected that takes the same parameters as the constructor and returns
an object of the appropriate type. Constructors are referenced by using the :: operator and
adding the class name. Consider the following function that expects a function parameter with no
parameters and return type Foo :
class Foo
Using ::Foo , the zero-argument constructor of the class Foo, we can simply call it like this:
function(::Foo)
Callable references to constructors are typed as one of the KFunction<out R> subtypes ,
depending on the parameter count.
Instead of calling the method matches directly we are storing a reference to it. Such reference is
bound to its receiver. It can be called directly (like in the example above) or used whenever an
expression of function type is expected:
214
val numberRegex = "\\d+".toRegex()
val strings = listOf("abc", "124", "a70")
println(strings.filter(numberRegex::matches))
Compare the types of bound and the corresponding unbound references. Bound callable
reference has its receiver "attached" to it, so the type of the receiver is no longer a parameter:
Since Kotlin 1.2, explicitly specifying this as the receiver is not necessary: this::foo and
::foo are equivalent.
class Outer {
inner class Inner
}
val o = Outer()
val boundInnerCtor = o::Inner
215
Type-Safe Builders
By using well-named functions as builders in combination with function literals with receiver it is
possible to create type-safe, statically-typed builders in Kotlin.
Type-safe builders allow creating Kotlin-based domain-speci c languages (DSLs) suitable for
building complex hierarchical data structures in a semi-declarative way. Some of the example use
cases for the builders are:
fun result() =
html {
head {
title {+"XML encoding with Kotlin"}
}
body {
h1 {+"XML encoding with Kotlin"}
p {+"this format can be used as an alternative markup to XML"}
// mixed content
p {
+"This is some"
b {+"mixed"}
+"text. For more see the"
216
+"text. For more see the"
a(href = "http://kotlinlang.org") {+"Kotlin"}
+"project"
}
p {+"some text"}
// content generated by
p {
for (arg in args)
+arg
}
}
}
This is completely legitimate Kotlin code. You can play with this code online (modify it and run in
the browser) here.
How it works
Let's walk through the mechanisms of implementing type-safe builders in Kotlin. First of all, we
need to de ne the model we want to build, in this case we need to model HTML tags. It is easily
done with a bunch of classes. For example, HTML is a class that describes the <html> tag, i.e. it
de nes children like <head> and <body> . (See its declaration below.)
Now, let's recall why we can say something like this in the code:
html {
// ...
}
html is actually a function call that takes a lambda expression as an argument. This function is
de ned as follows:
This function takes one parameter named init , which is itself a function. The type of the function
is HTML.() -> Unit , which is a function type with receiver. This means that we need to pass an
instance of type HTML (a receiver) to the function, and we can call members of that instance inside
the function. The receiver can be accessed through the this keyword:
html {
this.head { ... }
this.body { ... }
}
Now, this can be omitted, as usual, and we get something that looks very much like a builder
already:
217
html {
head { ... }
body { ... }
}
So, what does this call do? Let's look at the body of html function as de ned above. It creates a
new instance of HTML , then it initializes it by calling the function that is passed as an argument (in
our example this boils down to calling head and body on the HTML instance), and then it returns
this instance. This is exactly what a builder should do.
The head and body functions in the HTML class are de ned similarly to html . The only
di erence is that they add the built instances to the children collection of the enclosing HTML
instance:
Actually these two functions do just the same thing, so we can have a generic version, initTag :
One other thing to be discussed here is how we add text to tag bodies. In the example above we
say something like:
html {
head {
title {+"XML encoding with Kotlin"}
}
// ...
}
218
So basically, we just put a string inside a tag body, but there is this little + in front of it, so it is a
function call that invokes a pre x unaryPlus() operation. That operation is actually de ned by
an extension function unaryPlus() that is a member of the TagWithText abstract class (a
parent of Title ):
So, what the pre x + does here is wrapping a string into an instance of TextElement and adding
it to the children collection, so that it becomes a proper part of the tag tree.
All this is de ned in a package com.example.html that is imported at the top of the builder
example above. In the last section you can read through the full de nition of this package.
html {
head {
head {} // should be forbidden
}
// ...
}
In this example only members of the nearest implicit receiver this@head must be available;
head() is a member of the outer receiver this@html , so it must be illegal to call it.
To address this problem, in Kotlin 1.1 a special mechanism to control receiver scope was
introduced.
To make the compiler start controlling scopes we only have to annotate the types of all receivers
used in the DSL with the same marker annotation. For instance, for HTML Builders we declare an
annotation @HTMLTagMarker :
@DslMarker
annotation class HtmlTagMarker
An annotation class is called a DSL marker if it is annotated with the @DslMarker annotation.
In our DSL all the tag classes extend the same superclass Tag . It's enough to annotate only the
superclass with @HtmlTagMarker and after that the Kotlin compiler will treat all the inherited
classes as annotated:
@HtmlTagMarker
abstract class Tag(val name: String) { ... }
219
We don't have to annotate the HTML or Head classes with @HtmlTagMarker because their
superclass is already annotated:
After we've added this annotation, the Kotlin compiler knows which implicit receivers are part of
the same DSL and allows to call members of the nearest receivers only:
html {
head {
head { } // error: a member of outer receiver
}
// ...
}
Note that it's still possible to call the members of the outer receiver, but to do that you have to
specify this receiver explicitly:
html {
head {
[email protected] { } // possible
}
// ...
}
Note that the @DslMarker annotation is available only since Kotlin 1.1.
package com.example.html
interface Element {
fun render(builder: StringBuilder, indent: String)
}
@DslMarker
annotation class HtmlTagMarker
@HtmlTagMarker
abstract class Tag(val name: String) : Element {
val children = arrayListOf<Element>()
val attributes = hashMapOf<String, String>()
220
protected fun <T : Element> initTag(tag: T, init: T.() -> Unit): T {
tag.init()
children.add(tag)
return tag
}
class A : BodyTag("a") {
221
var href: String
get() = attributes["href"]!!
set(value) {
attributes["href"] = value
}
}
222
Type aliases
Type aliases provide alternative names for existing types. If the type name is too long you can
introduce a di erent shorter name and use the new one instead.
It's useful to shorten long generic types. For instance, it's often tempting to shrink collection types:
You can have new names for inner and nested classes:
class A {
inner class Inner
}
class B {
inner class Inner
}
Type aliases do not introduce new types. They are equivalent to the corresponding underlying
types. When you add typealias Predicate<T> and use Predicate<Int> in your code, the
Kotlin compiler always expand it to (Int) -> Boolean . Thus you can pass a variable of your
type whenever a general function type is required and vice versa:
fun main() {
val f: (Int) -> Boolean = { it > 0 }
println(foo(f)) // prints "true"
223
Reference
Keywords and Operators
Hard Keywords
The following tokens are always interpreted as keywords and cannot be used as identi ers:
— as
— else de nes the branch of an if expression which is executed when the condition is false
— if begins an if expression
— in
— !in
— is used as an operator to check that a value does NOT belong to a range, a collection or
another entity that de nes the 'contains' method
— is used in when expressions for the same purpose
224
— is
— !is
— null is a constant representing an object reference that doesn't point to any object
— super
— this
Soft Keywords
The following tokens act as keywords in the context when they are applicable and can be used as
identi ers in other contexts:
— by
225
— delegate is used as an annotation use-site target
— finally begins a block that is always executed when a try block exits
— get
— set
Modi er Keywords
The following tokens act as keywords in modi er lists of declarations and can be used as identi ers
in other contexts:
226
— final forbids overriding a member
— inline tells the compiler to inline the function and the lambdas passed to it at the call site
— inner allows referring to the outer class instance from a nested class
— protected marks a declaration as visible in the current class and its subclasses
— tailrec marks a function as tail-recursive (allowing the compiler to replace recursion with
iteration)
— vararg allows passing a variable number of arguments for a parameter
— field is used inside a property accessor to refer to the backing eld of the property
— + , - , * , / , % - mathematical operators
— =
— assignment operator
— is used to specify default values for parameters
227
— += , -= , *= , /= , %= - augmented assignment operators
— && , || , ! - logical 'and', 'or', 'not' operators (for bitwise operations, use corresponding in x
functions)
— == , != - equality operators (translated to calls of equals() for non-primitive types)
— < , > , <= , >= - comparison operators (translated to calls of compareTo() for non-primitive
types)
— [ , ] - indexed access operator (translated to calls of get and set )
— ?. performs a safe call (calls a method or accesses a property if the receiver is non-null)
— ?: takes the right-hand value if the left-hand value is null (the elvis operator)
— .. creates a range
— ->
— @
— introduces an annotation
— introduces or references a loop label
— introduces or references a lambda label
— references a 'this' expression from an outer scope
— references an outer superclass
— _
228
Grammar
Notation
This section informally explains the grammar notation used below.
EBNF expressions
Operator | denotes alternative.
Operator * denotes iteration (zero or more).
Operator + denotes iteration (one or more).
Operator ? denotes option (zero or one).
alpha { beta } denotes a nonempty beta-separated list of alpha's.
Operator ++ means that no space or comment is allowed between operands.
Semicolons
Kotlin provides "semicolon inference": syntactically, subsentences (e.g., statements, declarations
etc) are separated by the pseudo-token SEMI, which stands for "semicolon or newline". In most
cases, there's no need for semicolons in Kotlin code.
Syntax
Relevant pages: Packages
start
kotlinFile
: preamble topLevelObject*
;
start
script
: preamble expression*
;
preamble
(used by script, kotlinFile)
: fileAnnotations? packageHeader? import*
;
fileAnnotations
(used by preamble)
: fileAnnotation*
;
fileAnnotation
(used by fileAnnotations)
: "@" "file" ":" ("[" unescapedAnnotation+ "]" | unescapedAnnotation)
;
packageHeader
(used by preamble)
: modifiers "package" SimpleName{"."} SEMI?
;
See Packages
import
229
(used by preamble)
: "import" SimpleName{"."} ("." "*" | "as" SimpleName)? SEMI?
;
See Imports
topLevelObject
(used by kotlinFile)
: class
: object
: function
: property
: typeAlias
;
typeAlias
(used by memberDeclaration, declaration, topLevelObject)
: modifiers "typealias" SimpleName typeParameters? "=" type
;
Classes
See Classes and Inheritance
class
(used by memberDeclaration, declaration, topLevelObject)
: modifiers ("class" | "interface") SimpleName
typeParameters?
primaryConstructor?
(":" annotations delegationSpecifier{","})?
typeConstraints
(classBody? | enumClassBody)
;
primaryConstructor
(used by class, object)
: (modifiers "constructor")? ("(" functionParameter{","} ")")
;
classBody
(used by objectLiteral, enumEntry, class, companionObject, object)
: ("{" members "}")?
;
members
(used by enumClassBody, classBody)
: memberDeclaration*
;
delegationSpecifier
(used by objectLiteral, class, companionObject, object)
: constructorInvocation
: userType
: explicitDelegation
;
explicitDelegation
(used by delegationSpecifier)
: userType "by" expression
;
typeParameters
(used by typeAlias, class, property, function)
: "<" typeParameter{","} ">"
;
typeParameter
(used by typeParameters)
: modifiers SimpleName (":" userType)?
;
See Generic classes
typeConstraints
(used by class, property, function)
: ("where" typeConstraint{","})?
;
typeConstraint
(used by typeConstraints)
: annotations SimpleName ":" type
;
See Generic constraints
Class members
memberDeclaration
230
(used by members)
: companionObject
: object
: function
: property
: class
: typeAlias
: anonymousInitializer
: secondaryConstructor
;
anonymousInitializer
(used by memberDeclaration)
: "init" block
;
companionObject
(used by memberDeclaration)
: modifiers "companion" "object" SimpleName? (":" delegationSpecifier{","})? classBody?
;
valueParameters
(used by secondaryConstructor, function)
: "(" functionParameter{","}? ")"
;
functionParameter
(used by valueParameters, primaryConstructor)
: modifiers ("val" | "var")? parameter ("=" expression)?
;
block
(used by catchBlock, anonymousInitializer, secondaryConstructor, functionBody, controlStructureBody, try,
finallyBlock)
: "{" statements "}"
;
function
(used by memberDeclaration, declaration, topLevelObject)
: modifiers "fun"
typeParameters?
(type ".")?
SimpleName
typeParameters? valueParameters (":" type)?
typeConstraints
functionBody?
;
functionBody
(used by getter, setter, function)
: block
: "=" expression
;
variableDeclarationEntry
(used by for, lambdaParameter, property, multipleVariableDeclarations)
: SimpleName (":" type)?
;
multipleVariableDeclarations
(used by for, lambdaParameter, property)
: "(" variableDeclarationEntry{","} ")"
;
property
(used by memberDeclaration, declaration, topLevelObject)
: modifiers ("val" | "var")
typeParameters?
(type ".")?
(multipleVariableDeclarations | variableDeclarationEntry)
typeConstraints
("by" | "=" expression SEMI?)?
(getter? setter? | setter? getter?) SEMI?
;
See Properties and Fields
getter
(used by property)
: modifiers "get"
: modifiers "get" "(" ")" (":" type)? functionBody
;
setter
(used by property)
: modifiers "set"
: modifiers "set" "(" modifiers (SimpleName | parameter) ")" functionBody
;
parameter
(used by functionType, setter, functionParameter)
: SimpleName ":" type
;
object
(used by memberDeclaration, declaration, topLevelObject)
231
: modifiers "object" SimpleName primaryConstructor? (":" delegationSpecifier{","})? classBody?
;
secondaryConstructor
(used by memberDeclaration)
: modifiers "constructor" valueParameters (":" constructorDelegationCall)? block
;
constructorDelegationCall
(used by secondaryConstructor)
: "this" valueArguments
: "super" valueArguments
;
See Object expressions and Declarations
Enum classes
Types
See Types
type
(used by namedInfix, simpleUserType, getter, atomicExpression, whenCondition, property, typeArguments,
function, typeAlias, parameter, functionType, variableDeclarationEntry, lambdaParameter, typeConstraint)
: typeModifiers typeReference
;
typeReference
(used by typeReference, nullableType, type)
: "(" typeReference ")"
: functionType
: userType
: nullableType
: "dynamic"
;
nullableType
(used by typeReference)
: typeReference "?"
;
userType
(used by typeParameter, catchBlock, callableReference, typeReference, delegationSpecifier,
constructorInvocation, explicitDelegation)
: simpleUserType{"."}
;
simpleUserType
(used by userType)
: SimpleName ("<" (projection? type | "*"){","} ">")?
;
projection
(used by simpleUserType)
: varianceAnnotation
;
functionType
(used by typeReference)
: (type ".")? "(" parameter{","}? ")" "->" type
;
Control structures
See Control structures
controlStructureBody
(used by whenEntry, for, if, doWhile, while)
232
: block
: blockLevelExpression
;
if
(used by atomicExpression)
: "if" "(" expression ")" controlStructureBody SEMI? ("else" controlStructureBody)?
;
try
(used by atomicExpression)
: "try" block catchBlock* finallyBlock?
;
catchBlock
(used by try)
: "catch" "(" annotations SimpleName ":" userType ")" block
;
finallyBlock
(used by try)
: "finally" block
;
loop
(used by atomicExpression)
: for
: while
: doWhile
;
for
(used by loop)
: "for" "
(" annotations (multipleVariableDeclarations | variableDeclarationEntry) "in" expression ")" controlStructureBody
;
while
(used by loop)
: "while" "(" expression ")" controlStructureBody
;
doWhile
(used by loop)
: "do" controlStructureBody "while" "(" expression ")"
;
Expressions
Precedence
Precedence Title Symbols
Highest Postfix ++, --, ., ?., ?
Prefix -, +, ++, --, !, labelDefinition
Type RHS :, as, as?
Multiplicative *, /, %
Additive +, -
Range ..
Infix function SimpleName
Elvis ?:
Named checks in, !in, is, !is
Comparison <, >, <=, >=
Equality ==, !==
Conjunction &&
Disjunction ||
Lowest Assignment =, +=, -=, *=, /=, %=
Rules
expression
(used by for, atomicExpression, longTemplate, whenCondition, functionBody, doWhile, property, script,
explicitDelegation, jump, while, arrayAccess, blockLevelExpression, collectionLiteral, if, when, valueArguments,
functionParameter)
233
: disjunction (assignmentOperator disjunction)*
;
disjunction
(used by expression)
: conjunction ("||" conjunction)*
;
conjunction
(used by disjunction)
: equalityComparison ("&&" equalityComparison)*
;
equalityComparison
(used by conjunction)
: comparison (equalityOperation comparison)*
;
comparison
(used by equalityComparison)
: namedInfix (comparisonOperation namedInfix)*
;
namedInfix
(used by comparison)
: elvisExpression (inOperation elvisExpression)*
: elvisExpression (isOperation type)?
;
elvisExpression
(used by namedInfix)
: infixFunctionCall ("?:" infixFunctionCall)*
;
infixFunctionCall
(used by elvisExpression)
: rangeExpression (SimpleName rangeExpression)*
;
rangeExpression
(used by infixFunctionCall)
: additiveExpression (".." additiveExpression)*
;
additiveExpression
(used by rangeExpression)
: multiplicativeExpression (additiveOperation multiplicativeExpression)*
;
multiplicativeExpression
(used by additiveExpression)
: typeRHS (multiplicativeOperation typeRHS)*
;
typeRHS
(used by multiplicativeExpression)
: prefixUnaryExpression (typeOperation prefixUnaryExpression)*
;
prefixUnaryExpression
(used by typeRHS)
: prefixUnaryOperation* postfixUnaryExpression
;
postfixUnaryExpression
(used by prefixUnaryExpression, postfixUnaryOperation)
: atomicExpression postfixUnaryOperation*
: callableReference postfixUnaryOperation*
;
callableReference
(used by postfixUnaryExpression)
: (userType "?"*)? "::" SimpleName typeArguments?
;
atomicExpression
(used by postfixUnaryExpression)
: "(" expression ")"
: literalConstant
: functionLiteral
: "this" labelReference?
: "super" ("<" type ">")? labelReference?
: if
: when
: try
: objectLiteral
: jump
: loop
: collectionLiteral
: SimpleName
;
labelReference
(used by atomicExpression, jump)
: "@" ++ LabelName
;
labelDefinition
(used by prefixUnaryOperation, annotatedLambda)
234
: LabelName ++ "@"
;
literalConstant
(used by atomicExpression)
: "true" | "false"
: stringTemplate
: NoEscapeString
: IntegerLiteral
: CharacterLiteral
: FloatLiteral
: "null"
;
stringTemplate
(used by literalConstant)
: "\"" stringTemplateElement* "\""
;
stringTemplateElement
(used by stringTemplate)
: RegularStringPart
: ShortTemplateEntryStart (SimpleName | "this")
: EscapeSequence
: longTemplate
;
longTemplate
(used by stringTemplateElement)
: "${" expression "}"
;
declaration
(used by statement)
: function
: property
: class
: typeAlias
: object
;
statement
(used by statements)
: declaration
: blockLevelExpression
;
blockLevelExpression
(used by statement, controlStructureBody)
: annotations ("\n")+ expression
;
multiplicativeOperation
(used by multiplicativeExpression)
: "*" : "/" : "%"
;
additiveOperation
(used by additiveExpression)
: "+" : "-"
;
inOperation
(used by namedInfix)
: "in" : "!in"
;
typeOperation
(used by typeRHS)
: "as" : "as?" : ":"
;
isOperation
(used by namedInfix)
: "is" : "!is"
;
comparisonOperation
(used by comparison)
: "<" : ">" : ">=" : "<="
;
equalityOperation
(used by equalityComparison)
: "!=" : "=="
;
assignmentOperator
(used by expression)
: "="
: "+=" : "-=" : "*=" : "/=" : "%="
;
prefixUnaryOperation
(used by prefixUnaryExpression)
: "-" : "+"
: "++" : "--"
: "!"
235
: annotations
: labelDefinition
;
postfixUnaryOperation
(used by postfixUnaryExpression)
: "++" : "--" : "!!"
: callSuffix
: arrayAccess
: memberAccessOperation postfixUnaryExpression
;
callSuffix
(used by constructorInvocation, postfixUnaryOperation)
: typeArguments? valueArguments annotatedLambda
: typeArguments annotatedLambda
;
annotatedLambda
(used by callSuffix)
: ("@" unescapedAnnotation)* labelDefinition? functionLiteral
;
memberAccessOperation
(used by postfixUnaryOperation)
: "." : "?." : "?"
;
typeArguments
(used by callSuffix, callableReference, unescapedAnnotation)
: "<" type{","} ">"
;
valueArguments
(used by callSuffix, enumEntry, constructorDelegationCall, unescapedAnnotation)
: "(" ((SimpleName "=")? "*"? expression){","} ")"
;
jump
(used by atomicExpression)
: "throw" expression
: "return" ++ labelReference? expression?
: "continue" ++ labelReference?
: "break" ++ labelReference?
;
functionLiteral
(used by atomicExpression, annotatedLambda)
: "{" statements "}"
: "{" lambdaParameter{","} "->" statements "}"
;
lambdaParameter
(used by functionLiteral)
: variableDeclarationEntry
: multipleVariableDeclarations (":" type)?
;
statements
(used by block, functionLiteral)
: SEMI* statement{SEMI+} SEMI*
;
constructorInvocation
(used by delegationSpecifier)
: userType callSuffix
;
arrayAccess
(used by postfixUnaryOperation)
: "[" expression{","} "]"
;
objectLiteral
(used by atomicExpression)
: "object" (":" delegationSpecifier{","})? classBody
;
collectionLiteral
(used by atomicExpression)
: "[" expression{","}? "]"
;
When-expression
See When-expression
when
(used by atomicExpression)
: "when" ("(" expression ")")? "{"
whenEntry*
"}"
;
whenEntry
(used by when)
236
: whenCondition{","} "->" controlStructureBody SEMI
: "else" "->" controlStructureBody SEMI
;
whenCondition
(used by whenEntry)
: expression
: ("in" | "!in") expression
: ("is" | "!is") type
;
Modi ers
modifiers
(used by typeParameter, getter, packageHeader, class, property, object, function, typeAlias,
secondaryConstructor, enumEntry, setter, companionObject, primaryConstructor, functionParameter)
: (modifier | annotations)*
;
typeModifiers
(used by type)
: (suspendModifier | annotations)*
;
modifier
(used by modifiers)
: classModifier
: accessModifier
: varianceAnnotation
: memberModifier
: parameterModifier
: typeParameterModifier
: functionModifier
: propertyModifier
: multiPlatformModifier
;
classModifier
(used by modifier)
: "abstract"
: "final"
: "enum"
: "open"
: "annotation"
: "sealed"
: "data"
;
memberModifier
(used by modifier)
: "override"
: "open"
: "final"
: "abstract"
: "lateinit"
;
accessModifier
(used by modifier)
: "private"
: "protected"
: "public"
: "internal"
;
varianceAnnotation
(used by modifier, projection)
: "in"
: "out"
;
parameterModifier
(used by modifier)
: "noinline"
: "crossinline"
: "vararg"
;
typeParameterModifier
(used by modifier)
: "reified"
;
functionModifier
(used by modifier)
: "tailrec"
: "operator"
: "infix"
: "inline"
: "external"
: suspendModifier
237
;
propertyModifier
(used by modifier)
: "const"
;
suspendModifier
(used by typeModifiers, functionModifier)
: "suspend"
;
multiPlatformModifier
(used by modifier)
: "expect"
: "actual"
;
Annotations
annotations
(used by catchBlock, prefixUnaryOperation, blockLevelExpression, for, typeModifiers, class, modifiers,
typeConstraint)
: (annotation | annotationList)*
;
annotation
(used by annotations)
: "@" (annotationUseSiteTarget ":")? unescapedAnnotation
;
annotationList
(used by annotations)
: "@" (annotationUseSiteTarget ":")? "[" unescapedAnnotation+ "]"
;
annotationUseSiteTarget
(used by annotation, annotationList)
: "field"
: "file"
: "property"
: "get"
: "set"
: "receiver"
: "param"
: "setparam"
: "delegate"
;
unescapedAnnotation
(used by annotation, fileAnnotation, annotatedLambda, annotationList)
: SimpleName{"."} typeArguments? valueArguments?
;
Lexical structure
helper
LongSuffix
(used by IntegerLiteral)
: "L"
;
IntegerLiteral
(used by literalConstant)
: DecimalLiteral LongSuffix?
: HexadecimalLiteral LongSuffix?
: BinaryLiteral LongSuffix?
;
helper
Digit
(used by DecimalLiteral, HexDigit)
: ["0".."9"]
;
DecimalLiteral
(used by IntegerLiteral)
: Digit
: Digit (Digit | "_")* Digit
;
FloatLiteral
(used by literalConstant)
: <Java double literal>
;
helper
HexDigit
(used by HexadecimalLiteral, UnicodeEscapeSequence)
: Digit | ["A".."F", "a".."f"]
;
HexadecimalLiteral
(used by IntegerLiteral)
: "0" ("x" | "X") HexDigit
238
: "0" ("x" | "X") HexDigit (HexDigit | "_")* HexDigit
;
helper
BinaryDigit
(used by BinaryLiteral)
: ("0" | "1")
;
BinaryLiteral
(used by IntegerLiteral)
: "0" ("b" | "B") BinaryDigit
: "0" ("b" | "B") BinaryDigit (BinaryDigit | "_")* BinaryDigit
CharacterLiteral
(used by literalConstant)
: <character as in Java>
;
See Basic types
NoEscapeString
(used by literalConstant)
: <"""-quoted string>
;
RegularStringPart
(used by stringTemplateElement)
: <any character other than backslash, quote, $ or newline>
;
ShortTemplateEntryStart
(used by stringTemplateElement)
: "$"
;
EscapeSequence
(used by stringTemplateElement)
: UnicodeEscapeSequence | RegularEscapeSequence
;
UnicodeEscapeSequence
(used by EscapeSequence)
: "\u" HexDigit{4}
;
RegularEscapeSequence
(used by EscapeSequence)
: "\" <any character other than newline>
;
See String templates
SEMI
(used by whenEntry, if, statements, packageHeader, property, import)
: <semicolon or newline>
;
SimpleName
(used by typeParameter, catchBlock, simpleUserType, atomicExpression, LabelName, packageHeader, class,
object, infixFunctionCall, function, typeAlias, parameter, callableReference, variableDeclarationEntry,
stringTemplateElement, enumEntry, setter, import, companionObject, valueArguments, unescapedAnnotation,
typeConstraint)
: <java identifier>
: "`" <java identifier> "`"
;
See Java interoperability
LabelName
(used by labelReference, labelDefinition)
: SimpleName
;
See Returns and jumps
239
Java Interop
Calling Java code from Kotlin
Kotlin is designed with Java Interoperability in mind. Existing Java code can be called from Kotlin in
a natural way, and Kotlin code can be used from Java rather smoothly as well. In this section we
describe some details about calling Java code from Kotlin.
Pretty much all Java code can be used without any issues:
import java.util.*
For example:
import java.util.Calendar
fun calendarDemo() {
val calendar = Calendar.getInstance()
if (calendar.firstDayOfWeek == Calendar.SUNDAY) { // call getFirstDayOfWeek()
calendar.firstDayOfWeek = Calendar.MONDAY // call setFirstDayOfWeek()
}
if (!calendar.isLenient) { // call isLenient()
calendar.isLenient = true // call setLenient()
}
}
240
Note that, if the Java class only has a setter, it will not be visible as a property in Kotlin, because
Kotlin does not support set-only properties at this time.
foo.`is`(bar)
When we call methods on variables of platform types, Kotlin does not issue nullability errors at
compile time, but the call may fail at runtime, because of a null-pointer exception or an assertion
that Kotlin generates to prevent nulls from propagating:
Platform types are non-denotable, meaning that one can not write them down explicitly in the
language. When a platform value is assigned to a Kotlin variable, we can rely on type inference (the
variable will have an inferred platform type then, as item has in the example above), or we can
choose the type that we expect (both nullable and non-null types are allowed):
241
If we choose a non-null type, the compiler will emit an assertion upon assignment. This prevents
Kotlin's non-null variables from holding nulls. Assertions are also emitted when we pass platform
values to Kotlin functions expecting non-null values etc. Overall, the compiler does its best to
prevent nulls from propagating far through the program (although sometimes this is impossible to
eliminate entirely, because of generics).
As mentioned above, platform types cannot be mentioned explicitly in the program, so there's no
syntax for them in the language. Nevertheless, the compiler and IDE need to display them
sometimes (in error messages, parameter info etc), so we have a mnemonic notation for them:
Nullability annotations
Java types which have nullability annotations are represented not as platform types, but as actual
nullable or non-null Kotlin types. The compiler supports several avors of nullability annotations,
including:
— FindBugs ( edu.umd.cs.findbugs.annotations )
— Eclipse ( org.eclipse.jdt.annotation )
— Lombok ( lombok.NonNull ).
You can nd the full list in the Kotlin compiler source code.
It is possible to annotate type arguments of generic types to provide nullability information for
them as well. For example, consider these annotations on a Java declaration:
@NotNull
Set<@NotNull String> toSet(@NotNull Collection<@NotNull String> elements) { ... }
242
Note the @NotNull annotations on String type arguments. Without them, we get platform
types in the type arguments:
Annotating type arguments works with Java 8 target or higher and requires the nullability
annotations to support the TYPE_USE target ( org.jetbrains.annotations supports this in
version 15 and above).
Note: due to the current technical limitations, the IDE does not correctly recognize these
annotations on type arguments in compiled Java libraries that are used as dependencies.
JSR-305 Support
The @Nonnull annotation de ned in JSR-305 is supported for denoting nullability of Java types.
If the @Nonnull(when = ...) value is When.ALWAYS , the annotated type is treated as non-
null; When.MAYBE and When.NEVER denote a nullable type; and When.UNKNOWN forces the type
to be platform one.
A library can be compiled against the JSR-305 annotations, but there's no need to make the
annotations artifact (e.g. jsr305.jar ) a compile dependency for the library consumers. The
Kotlin compiler can read the JSR-305 annotations from a library without the annotations present on
the classpath.
Since Kotlin 1.1.50, custom nullability quali ers (KEEP-79) are also supported (see below).
243
@TypeQualifierNickname
@Nonnull(when = When.ALWAYS)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyNonnull {
}
@TypeQualifierNickname
@CheckForNull // a nickname to another type qualifier nickname
@Retention(RetentionPolicy.RUNTIME)
public @interface MyNullable {
}
interface A {
@MyNullable String foo(@MyNonnull String x);
// in Kotlin (strict mode): `fun foo(x: String): String?`
Such annotation type should itself be annotated with both @Nonnull (or its nickname) and
@TypeQualifierDefault(...) with one or more ElementType values:
— ElementType.TYPE_USE (since 1.1.60) for any type including type arguments, upper bounds
of type parameters and wildcard types.
The default nullability is used when a type itself is not annotated by a nullability annotation, and
the default is determined by the innermost enclosing element annotated with a type quali er
default annotation with the ElementType matching the type usage.
244
@Nonnull
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER})
public @interface NonNullApi {
}
@Nonnull(when = When.MAYBE)
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE_USE})
public @interface NullableApi {
}
@NullableApi
interface A {
String foo(String x); // fun foo(x: String?): String?
Note: the types in this example only take place with the strict mode enabled, otherwise, the
platform types remain. See the @UnderMigration annotation and Compiler con guration
sections.
// FILE: test/package-info.java
@NonNullApi // declaring all types in package 'test' as non-nullable by default
package test;
The status value in @UnderMigration(status = ...) speci es how the compiler treats
inappropriate usages of the annotated types in Kotlin (e.g. using a @MyNullable -annotated type
value as non-null):
245
A library maintainer can add @UnderMigration status to both type quali er nicknames and type
quali er defaults:
@Nonnull(when = When.ALWAYS)
@TypeQualifierDefault({ElementType.METHOD, ElementType.PARAMETER})
@UnderMigration(status = MigrationStatus.WARN)
public @interface NonNullApi {
}
// The types in the class are non-null, but only warnings are reported
// because `@NonNullApi` is annotated `@UnderMigration(status = MigrationStatus.WARN)`
@NonNullApi
public class Test {}
Note: the migration status of a nullability annotation is not inherited by its type quali er nicknames
but is applied to its usages in default type quali ers.
If a default type quali er uses a type quali er nickname and they are both @UnderMigration , the
status from the default type quali er is used.
The JSR-305 checks can be con gured by adding the -Xjsr305 compiler ag with the following
options (and their combination):
spread among many well-known libraries, and users may need to migrate smoothly when
updating to the Kotlin version containing JSR-305 support. Since Kotlin 1.1.60, this ag only
a ects non- @UnderMigration annotations.
The strict , warn and ignore values have the same meaning as those of MigrationStatus ,
and only the strict mode a ects the types in the annotated declarations as they are seen in
Kotlin.
246
Note: the built-in JSR-305 annotations @Nonnull, @Nullable and @CheckForNull are always
enabled and a ect the types of the annotated declarations in Kotlin, regardless of compiler
con guration with the -Xjsr305 ag.
For kotlin versions 1.1.50+/1.2, the default behavior is the same to -Xjsr305=warn . The strict
value should be considered experimental (more checks may be added to it in the future).
Mapped types
Kotlin treats some Java types specially. Such types are not loaded from Java "as is", but are mapped
to corresponding Kotlin types. The mapping only matters at compile time, the runtime
representation remains unchanged. Java's primitive types are mapped to corresponding Kotlin
types (keeping platform types in mind):
247
Java type Kotlin type
java.lang.Byte kotlin.Byte?
java.lang.Short kotlin.Short?
java.lang.Integer kotlin.Int?
java.lang.Long kotlin.Long?
java.lang.Character kotlin.Char?
java.lang.Float kotlin.Float?
java.lang.Double kotlin.Double?
java.lang.Boolean kotlin.Boolean?
Note that a boxed primitive type used as a type parameter is mapped to a platform type: for
example, List<java.lang.Integer> becomes a List<Int!> in Kotlin.
Collection types may be read-only or mutable in Kotlin, so Java's collections are mapped as follows
(all Kotlin types in this table reside in the package kotlin.collections ):
Java type Kotlin read-only Kotlin mutable type Loaded platform type
type
Iterator<T> Iterator<T> MutableIterator<T> (Mutable)Iterator<T>!
Iterable<T> Iterable<T> MutableIterable<T> (Mutable)Iterable<T>!
Collection<T> Collection<T> MutableCollection<T> (Mutable)Collection<T>!
Set<T> Set<T> MutableSet<T> (Mutable)Set<T>!
List<T> List<T> MutableList<T> (Mutable)List<T>!
ListIterator<T> ListIterator<T> MutableListIterator<T> (Mutable)ListIterator<T>!
Map<K, V> Map<K, V> MutableMap<K, V> (Mutable)Map<K, V>!
Map.Entry<K, V> Map.Entry<K, V> MutableMap.MutableEntry<K,V> (Mutable)Map.
(Mutable)Entry<K, V>!
Note: the static members of these Java types are not directly accessible on the companion objects
of the Kotlin types. To call them, use the full quali ed names of the Java types, e.g.
java.lang.Integer.toHexString(foo) .
248
List becomes List<*>! , i.e. List<out Any?>! .
—
Like Java's, Kotlin's generics are not retained at runtime, i.e. objects do not carry information about
actual type arguments passed to their constructors, i.e. ArrayList<Integer>() is
indistinguishable from ArrayList<Character>() . This makes it impossible to perform is-
checks that take generics into account. Kotlin only allows is-checks for star-projected generic
types:
Java Arrays
Arrays in Kotlin are invariant, unlike Java. This means that Kotlin does not let us assign an
Array<String> to an Array<Any> , which prevents a possible runtime failure. Passing an array
of a subclass as an array of superclass to a Kotlin method is also prohibited, but for Java methods
this is allowed (through platform types of the form Array<(out) String>! ).
Arrays are used with primitive datatypes on the Java platform to avoid the cost of boxing/unboxing
operations. As Kotlin hides those implementation details, a workaround is required to interface
with Java code. There are specialized classes for every type of primitive array ( IntArray ,
DoubleArray , CharArray , and so on) to handle this case. They are not related to the Array
class and are compiled down to Java's primitive arrays for maximum performance.
When compiling to JVM byte codes, the compiler optimizes access to arrays so that there's no
overhead introduced:
Even when we navigate with an index, it does not introduce any overhead:
249
for (i in array.indices) { // no iterator created
array[i] += 2
}
Java Varargs
Java classes sometimes use a method declaration for the indices with a variable number of
arguments (varargs):
In that case you need to use the spread operator * to pass the IntArray :
It's currently not possible to pass null to a method that is declared as varargs.
Operators
Since Java has no way of marking methods for which it makes sense to use the operator syntax,
Kotlin allows using any Java methods with the right name and signature as operator overloads and
other conventions ( invoke() etc.) Calling Java methods using the in x call syntax is not allowed.
Checked Exceptions
In Kotlin, all exceptions are unchecked, meaning that the compiler does not force you to catch any
of them. So, when you call a Java method that declares a checked exception, Kotlin does not force
you to do anything:
Object Methods
250
When Java types are imported into Kotlin, all the references of the type java.lang.Object are
turned into Any . Since Any is not platform-speci c, it only declares toString() , hashCode()
and equals() as its members, so to make other members of java.lang.Object available,
Kotlin uses extension functions.
wait()/notify()
Methods wait() and notify() are not available on references of type Any . Their usage is
generally discouraged in favor of java.utl.concurrent . If you really need to call these
methods, you can cast to java.lang.Object :
(foo as java.lang.Object).wait()
getClass()
To retrieve the Java class of an object, use the java extension property on a class reference:
The code above uses a bound class reference, which is supported since Kotlin 1.1. You can also use
the javaClass extension property:
clone()
Do not forget about E ective Java, 3rd Edition, Item 13: Override clone judiciously.
nalize()
To override finalize() , all you need to do is simply declare it, without using the override
keyword:
class C {
protected fun finalize() {
// finalization logic
}
}
251
At most one Java class (and as many Java interfaces as you like) can be a supertype for a class in
Kotlin.
if (Character.isLetter(a)) { ... }
To access static members of a Java type that is mapped to a Kotlin type, use the full quali ed name
of the Java type: java.lang.Integer.bitCount(foo) .
Java Re ection
Java re ection works on Kotlin classes and vice versa. As mentioned above, you can use
instance::class.java , ClassName::class.java or instance.javaClass to enter Java
re ection through java.lang.Class .
Other supported cases include acquiring a Java getter/setter method or a backing eld for a Kotlin
property, a KProperty for a Java eld, a Java method or constructor for a KFunction and vice
versa.
SAM Conversions
Just like Java 8, Kotlin supports SAM conversions. This means that Kotlin function literals can be
automatically converted into implementations of Java interfaces with a single non-default method,
as long as the parameter types of the interface method match the parameter types of the Kotlin
function.
If the Java class has multiple methods taking functional interfaces, you can choose the one you
need to call by using an adapter function that converts a lambda to a speci c SAM type. Those
adapter functions are also generated by the compiler when needed:
Note that SAM conversions only work for interfaces, not for abstract classes, even if those also have
just a single abstract method.
252
Also note that this feature works only for Java interop; since Kotlin has proper function types,
automatic conversion of functions into implementations of Kotlin interfaces is unnecessary and
therefore unsupported.
The rest of the procedure works in exactly the same way as in Java.
253
Calling Kotlin from Java
Kotlin code can be called from Java easily.
Properties
A Kotlin property is compiled to the following Java elements:
— A getter method, with the name calculated by prepending the get pre x;
— A setter method, with the name calculated by prepending the set pre x (only for var
properties);
— A private eld, with the same name as the property name (only for properties with backing
elds).
For example, var firstName: String gets compiled to the following Java declarations:
If the name of the property starts with is , a di erent name mapping rule is used: the name of the
getter will be the same as the property name, and the name of the setter will be obtained by
replacing is with set . For example, for a property isOpen , the getter will be called isOpen()
and the setter will be called setOpen() . This rule applies for properties of any type, not just
Boolean .
Package-Level Functions
All the functions and properties declared in a le example.kt inside a package org.foo.bar ,
including extension functions, are compiled into static methods of a Java class named
org.foo.bar.ExampleKt .
// example.kt
package demo
class Foo
// Java
new demo.Foo();
demo.ExampleKt.bar();
The name of the generated Java class can be changed using the @JvmName annotation:
254
@file:JvmName("DemoUtils")
package demo
class Foo
// Java
new demo.Foo();
demo.DemoUtils.bar();
Having multiple les which have the same generated Java class name (the same package and the
same name or the same @JvmName annotation) is normally an error. However, the compiler has
the ability to generate a single Java facade class which has the speci ed name and contains all the
declarations from all the les which have that name. To enable the generation of such a facade, use
the @JvmMulti leClass annotation in all of the les.
// oldutils.kt
@file:JvmName("Utils")
@file:JvmMultifileClass
package demo
// newutils.kt
@file:JvmName("Utils")
@file:JvmMultifileClass
package demo
// Java
demo.Utils.foo();
demo.Utils.bar();
Instance Fields
If you need to expose a Kotlin property as a eld in Java, you need to annotate it with the
@JvmField annotation. The eld will have the same visibility as the underlying property. You can
annotate a property with @JvmField if it has a backing eld, is not private, does not have open ,
override or const modi ers, and is not a delegated property.
255
// Java
class JavaClient {
public String getID(C c) {
return c.ID;
}
}
Late-Initialized properties are also exposed as elds. The visibility of the eld will be the same as
the visibility of lateinit property setter.
Static Fields
Kotlin properties declared in a named object or a companion object will have static backing elds
either in that named object or in the class containing the companion object.
Usually these elds are private but they can be exposed in one of the following ways:
— @JvmField annotation;
Annotating such a property with @JvmField makes it a static eld with the same visibility as the
property itself.
// Java
Key.COMPARATOR.compare(key1, key2);
// public static final field in Key class
A late-initialized property in an object or a companion object has a static backing eld with the
same visibility as the property setter.
object Singleton {
lateinit var provider: Provider
}
// Java
Singleton.provider = new Provider();
// public static non-final field in Singleton class
Properties annotated with const (in classes as well as at the top level) are turned into static elds
in Java:
256
// file example.kt
object Obj {
const val CONST = 1
}
class C {
companion object {
const val VERSION = 9
}
}
In Java:
int c = Obj.CONST;
int d = ExampleKt.MAX;
int v = C.VERSION;
Static Methods
As mentioned above, Kotlin represents package-level functions as static methods. Kotlin can also
generate static methods for functions de ned in named objects or companion objects if you
annotate those functions as @JvmStatic . If you use this annotation, the compiler will generate
both a static method in the enclosing class of the object and an instance method in the object itself.
For example:
class C {
companion object {
@JvmStatic fun foo() {}
fun bar() {}
}
}
object Obj {
@JvmStatic fun foo() {}
fun bar() {}
}
In Java:
257
@JvmStatic annotation can also be applied on a property of an object or a companion object
making its getter and setter methods be static members in that object or the class containing the
companion object.
Visibility
The Kotlin visibilities are mapped to Java in the following way:
— protected remains protected (note that Java allows accessing protected members from
other classes in the same package and Kotlin doesn't, so Java classes will have broader access to
the code);
— internal declarations become public in Java. Members of internal classes go through
name mangling, to make it harder to accidentally use them from Java and to allow overloading
for members with the same signature that don't see each other according to Kotlin rules;
— public remains public .
KClass
Sometimes you need to call a Kotlin method with a parameter of type KClass . There is no
automatic conversion from Class to KClass , so you have to do it manually by invoking the
equivalent of the Class<T>.kotlin extension property:
kotlin.jvm.JvmClassMappingKt.getKotlinClass(MainView.class)
These two functions can not be de ned side-by-side, because their JVM signatures are the same:
filterValid(Ljava/util/List;)Ljava/util/List; . If we really want them to have the
same name in Kotlin, we can annotate one (or both) of them with @JvmName and specify a
di erent name as an argument:
@JvmName("filterValidInt")
fun List<Int>.filterValid(): List<Int>
From Kotlin they will be accessible by the same name filterValid , but from Java it will be
filterValid and filterValidInt .
258
The same trick applies when we need to have a property x alongside with a function getX() :
val x: Int
@JvmName("getX_prop")
get() = 15
fun getX() = 10
To change the names of generated accessor methods for properties without explicitly
implemented getters and setters, you can use @get:JvmName and @set:JvmName :
@get:JvmName("x")
@set:JvmName("changeX")
var x: Int = 23
Overloads Generation
Normally, if you write a Kotlin function with default parameter values, it will be visible in Java only
as a full signature, with all parameters present. If you wish to expose multiple overloads to Java
callers, you can use the @JvmOverloads annotation.
The annotation also works for constructors, static methods etc. It can't be used on abstract
methods, including methods de ned in interfaces.
For every parameter with a default value, this will generate one additional overload, which has this
parameter and all parameters to the right of it in the parameter list removed. In this example, the
following will be generated:
// Constructors:
Foo(int x, double y)
Foo(int x)
// Methods
void f(String a, int b, String c) { }
void f(String a, int b) { }
void f(String a) { }
Note that, as described in Secondary Constructors, if a class has default values for all constructor
parameters, a public no-argument constructor will be generated for it. This works even if the
@JvmOverloads annotation is not speci ed.
Checked Exceptions
As we mentioned above, Kotlin does not have checked exceptions. So, normally, the Java signatures
of Kotlin functions do not declare exceptions thrown. Thus if we have a function in Kotlin like this:
259
// example.kt
package demo
fun foo() {
throw IOException()
}
// Java
try {
demo.Example.foo();
}
catch (IOException e) { // error: foo() does not declare IOException in the throws list
// ...
}
we get an error message from the Java compiler, because foo() does not declare IOException .
To work around this problem, use the @Throws annotation in Kotlin:
@Throws(IOException::class)
fun foo() {
throw IOException()
}
Null-safety
When calling Kotlin functions from Java, nobody prevents us from passing null as a non-null
parameter. That's why Kotlin generates runtime checks for all public functions that expect non-
nulls. This way we get a NullPointerException in the Java code immediately.
Variant generics
When Kotlin classes make use of declaration-site variance, there are two options of how their
usages are seen from the Java code. Let's say we have the following class and two functions that
use it:
interface Base
class Derived : Base
260
The problem is that in Kotlin we can say unboxBase(boxDerived("s")) , but in Java that would
be impossible, because in Java the class Box is invariant in its parameter T , and thus
Box<Derived> is not a subtype of Box<Base> . To make it work in Java we'd have to de ne
unboxBase as follows:
Here we make use of Java's wildcards types ( ? extends Base ) to emulate declaration-site
variance through use-site variance, because it is all Java has.
To make Kotlin APIs work in Java we generate Box<Super> as Box<? extends Super> for
covariantly de ned Box (or Foo<? super Bar> for contravariantly de ned Foo ) when it
appears as a parameter. When it's a return value, we don't generate wildcards, because otherwise
Java clients will have to deal with them (and it's against the common Java coding style). Therefore,
the functions from our example are actually translated as follows:
// parameter - wildcards
Base unboxBase(Box<? extends Base> box) { ... }
NOTE: when the argument type is nal, there's usually no point in generating the wildcard, so
Box<String> is always Box<String> , no matter what position it takes.
If we need wildcards where they are not generated by default, we can use the @JvmWildcard
annotation:
On the other hand, if we don't need wildcards where they are generated, we can use
@JvmSuppressWildcards :
NOTE: @JvmSuppressWildcards can be used not only on individual type arguments, but on
entire declarations, such as functions or classes, causing all wildcards inside them to be
suppressed.
The type Nothing is special, because it has no natural counterpart in Java. Indeed, every Java
reference type, including java.lang.Void , accepts null as a value, and Nothing doesn't
accept even that. So, this type cannot be accurately represented in the Java world. This is why Kotlin
generates a raw type where an argument of type Nothing is used:
261
fun emptyList(): List<Nothing> = listOf()
// is translated to
// List emptyList() { ... }
262
JavaScript
Dynamic Type
Being a statically typed language, Kotlin still has to interoperate with untyped or loosely typed
environments, such as the JavaScript ecosystem. To facilitate these use cases, the dynamic type is
available in the language:
— a value of this type can be assigned to any variable or passed anywhere as a parameter;
— any value can be assigned to a variable of type dynamic or passed to a function that takes
dynamic as a parameter;
— null -checks are disabled for such values.
The most peculiar feature of dynamic is that we are allowed to call any property or function with
any parameters on a dynamic variable:
On the JavaScript platform this code will be compiled "as is": dyn.whatever(1) in Kotlin
becomes dyn.whatever(1) in the generated JavaScript code.
When calling functions written in Kotlin on values of dynamic type, keep in mind the name
mangling performed by the Kotlin to JavaScript compiler. You may need to use the @JsName
annotation to assign well-de ned names to the functions that you need to call.
A dynamic call always returns dynamic as a result, so we can chain such calls freely:
dyn.foo().bar.baz()
When we pass a lambda to a dynamic call, all of its parameters by default have the type dynamic :
dyn.foo {
x -> x.bar() // x is dynamic
}
263
Expressions using values of dynamic type are translated to JavaScript "as is", and do not use the
Kotlin operator conventions. The following operators are supported:
— unary
— pre x: - , + , !
— assignments: += , -= , *= , /= , %=
— indexed access:
— read: d[a] , more than one argument is an error
264
Calling JavaScript from Kotlin
Kotlin was designed for easy interoperation with Java platform. It sees Java classes as Kotlin classes,
and Java sees Kotlin classes as Java classes. However, JavaScript is a dynamically-typed language,
which means it does not check types in compile-time. You can freely talk to JavaScript from Kotlin
via dynamic types, but if you want the full power of Kotlin type system, you can create Kotlin
headers for JavaScript libraries.
Inline JavaScript
You can inline some JavaScript code into your Kotlin code using the js("…") function. For example:
The parameter of js is required to be a string constant. So, the following code is incorrect:
external modi er
To tell Kotlin that a certain declaration is written in pure JavaScript, you should mark it with
external modi er. When the compiler sees such a declaration, it assumes that the
implementation for the corresponding class, function or property is provided by the developer,
and therefore does not try to generate any JavaScript code from the declaration. This means that
you should omit bodies of external declarations. For example:
// etc
}
Note that external modi er is inherited by nested declarations, i.e. in Node class we do not put
external before member functions and properties.
The external modi er is only allowed on package-level declarations. You can't declare an
external member of a non- external class.
265
In JavaScript you can de ne members either on a prototype or a class itself. I.e.:
There's no such syntax in Kotlin. However, in Kotlin we have companion objects. Kotlin treats
companion objects of external class in a special way: instead of expecting an object, it assumes
members of companion objects to be members of the class itself. To describe MyClass from the
example above, you can write:
fun ownMember()
}
An external function can have optional parameters. How the JavaScript implementation actually
computes default values for these parameters, is unknown to Kotlin, thus it's impossible to use the
usual syntax to declare such parameters in Kotlin. You should use the following syntax:
This means you can call myFunWithOptionalArgs with one required argument and two optional
arguments (their default values are calculated by some JavaScript code).
You can easily extend JavaScript classes as they were Kotlin classes. Just de ne an external class
and extend it by non- external class. For example:
1. When a function of external base class is overloaded by signature, you can't override it in a derived class.
266
external interfaces
JavaScript does not have the concept of interfaces. When a function expects its parameter to
support foo and bar methods, you just pass objects that actually have these methods. You can
use interfaces to express this for statically-typed Kotlin, for example:
fun bar()
}
Another use case for external interfaces is to describe settings objects. For example:
// etc
}
fun sendQuery() {
JQuery.get(JQueryAjaxSettings().apply {
complete = { (xhr, data) ->
window.alert("Request complete")
}
})
}
267
Calling Kotlin from JavaScript
Kotlin compiler generates normal JavaScript classes, functions and properties you can freely use
from JavaScript code. Nevertheless, there are some subtle things you should remember.
alert(myModule.foo());
This is not applicable when you compile your Kotlin module to JavaScript module (see JavaScript
Modules for more information on this). In this case there won't be a wrapper object, instead,
declarations will be exposed as a JavaScript module of a corresponding kind. For example, in case
of CommonJS you should write:
alert(require('myModule').foo());
Package structure
Kotlin exposes its package structure to JavaScript, so unless you de ne your declarations in the root
package, you have to use fully-quali ed names in JavaScript. For example:
package my.qualified.packagename
alert(myModule.my.qualified.packagename.foo());
@JsName annotation
In some cases (for example, to support overloads), Kotlin compiler mangles names of generated
functions and attributes in JavaScript code. To control the generated names, you can use the
@JsName annotation:
268
// Module 'kjs'
class Person(val name: String) {
fun hello() {
println("Hello $name!")
}
@JsName("helloWithGreeting")
fun hello(greeting: String) {
println("$greeting $name!")
}
}
Now you can use this class from JavaScript in the following way:
If we didn't specify the @JsName annotation, the name of the corresponding function would
contain a su x calculated from the function signature, for example hello_61zpoe$ .
Note that Kotlin compiler does not apply such mangling to external declarations, so you don't
have to use @JsName on them. Another case worth noticing is inheriting non-external classes from
external classes. In this case any overridden functions won't be mangled as well.
The parameter of @JsName is required to be a constant string literal which is a valid identi er. The
compiler will report an error on any attempt to pass non-identi er string to @JsName . The
following example produces a compile-time error:
— Kotlin can't distinguish between numeric types at run time (except for kotlin.Long ), i.e. the
following code works:
fun f() {
val x: Int = 23
val y: Any = x
println(y as Float)
}
269
— kotlin.Any is mapped to JavaScript Object (i.e. new Object() , {} , etc).
— Kotlin collections (i.e. List , Set , Map , etc) are not mapped to any speci c JavaScript type.
Starting with version 1.1.50 primitive array translation utilizes JavaScript TypedArray:
270
JavaScript Modules
Kotlin allows you to compile your Kotlin projects to JavaScript modules for popular module
systems. Here is the list of available options:
1. Plain. Don't compile for any module system. As usual, you can access a module by its name in the global scope. This
option is used by default.
3. CommonJS convention, widely used by node.js/npm ( require function and module.exports object)
4. Uni ed Module De nitions (UMD), which is compatible with both AMD and CommonJS, and works as "plain" when neither
AMD nor CommonJS is available at runtime.
Setup per module: Open File -> Project Structure…, nd your module in Modules and select "Kotlin"
facet under it. Choose appropriate module system in "Module kind" eld.
Setup for the whole project: Open File -> Settings, select "Build, Execution, Deployment" ->
"Compiler" -> "Kotlin compiler". Choose appropriate module system in "Module kind" eld.
From Maven
To select module system when compiling via Maven, you should set moduleKind con guration
property, i.e. your pom.xml should look like this:
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<goals>
<goal>js</goal>
</goals>
</execution>
</executions>
<!-- Insert these lines -->
<configuration>
<moduleKind>commonjs</moduleKind>
</configuration>
<!-- end of inserted text -->
</plugin>
From Gradle
271
To select module system when compiling via Gradle, you should set moduleKind property, i.e.
compileKotlin2Js.kotlinOptions.moduleKind = "commonjs"
@JsModule annotation
To tell Kotlin that an external class, package, function or property is a JavaScript module, you can
use @JsModule annotation. Consider you have the following CommonJS module called "hello":
@JsModule("hello")
external fun sayHello(name: String)
Some JavaScript libraries export packages (namespaces) instead of functions and classes. In terms
of JavaScript, it's an object that has members that are classes, functions and properties. Importing
these packages as Kotlin objects often looks unnatural. The compiler allows to map imported
JavaScript packages to Kotlin packages, using the following notation:
@file:JsModule("extModule")
package ext.jspackage.name
external class C
module.exports = {
foo: { /* some code here */ },
C: { /* some code here */ }
}
Important: les marked with @file:JsModule annotation can't declare non-external members.
The example below produces compile-time error:
@file:JsModule("extModule")
package ext.jspackage.name
272
In the previous example the JavaScript module exports a single package. However, some JavaScript
libraries export multiple packages from within a module. This case is also supported by Kotlin,
though you have to declare a new .kt le for each package you import.
module.exports = {
mylib: {
pkg1: {
foo: function() { /* some code here */ },
bar: function() { /* some code here */ }
},
pkg2: {
baz: function() { /* some code here */ }
}
}
}
To import this module in Kotlin, you have to write two Kotlin source les:
@file:JsModule("extModule")
@file:JsQualifier("mylib.pkg1")
package extlib.pkg1
and
@file:JsModule("extModule")
@file:JsQualifier("mylib.pkg2")
package extlib.pkg2
@JsNonModule annotation
When a declaration has @JsModule , you can't use it from Kotlin code when you don't compile it to
a JavaScript module. Usually, developers distribute their libraries both as JavaScript modules and
downloadable .js les that you can copy to project's static resources and include via <script>
element. To tell Kotlin that it's ok to use a @JsModule declaration from non-module environment,
you should put @JsNonModule declaration. For example, given JavaScript code:
273
@JsModule("hello")
@JsNonModule
@JsName("topLevelSayHello")
external fun sayHello(name: String)
Notes
Kotlin is distributed with kotlin.js standard library as a single le, which is itself compiled as an
UMD module, so you can use it with any module system described above. Also it is available on
NPM as kotlin package
274
JavaScript Re ection
At this time, JavaScript does not support the full Kotlin re ection API. The only supported part of
the API is the ::class syntax which allows you to refer to the class of an instance, or the class
corresponding to the given type. The value of a ::class expression is a stripped-down KClass
implementation that only supports the simpleName and isInstance members.
In addition to that, you can use KClass.js to access the JsClass instance corresponding to the class.
The JsClass instance itself is a reference to the constructor function. This can be used to
interoperate with JS functions that expect a reference to a constructor.
Examples:
class A
class B
class C
val a = A()
println(a::class.simpleName) // Obtains class for an instance; prints "A"
println(B::class.simpleName) // Obtains class for a type; prints "B"
println(B::class.js.name) // prints "B"
foo<C>() // prints "C"
275
JavaScript DCE
Since version 1.1.4, Kotlin/JS includes a dead code elimination (DCE) tool. This tool allows to strip
out unused properties, functions and classes from the generated JS. There are several ways you get
unused declarations:
— Functions can be inlined and never get called directly (which happens always except for few
situations).
— You are using a shared library which provides much more functions than you actually need. For
example, standard library ( kotlin.js ) contains functions for manipulating lists, arrays, char
sequences, adapters for DOM, etc, which together gives about 1.3 mb le. A simple "Hello,
world" application only requires console routines, which is only few kilobytes for the entire le.
How to use
DCE tool is currently available from Gradle.
Note that if you are using multi-project build, you should apply plugin to the main project that is an
entry point to your application.
By default, the resulting set of JavaScript les (your application together with all dependencies) can
be found at path $BUILD_DIR/min/ , where $BUILD_DIR is the path to generated JavaScript
(usually, build/classes/main ).
Con guring
To con gure DCE on the main source set, you can use the runDceKotlinJs task (and
corresponding runDce<sourceSetName>KotlinJs for other source sets).
Sometimes you are going to use a Kotlin declaration directly from JavaScript, and it's being stripped
out by DCE. You may want to keep this declaration. To do so, you can use the following syntax in
build.gradle :
For example, consider a module is named kotlin-js-example and it contains a function named
toKeep in package org.jetbrains.kotlin.examples . Use the following line:
runDceKotlinJs.keep "kotlin-js-example_main.org.jetbrains.kotlin.examples.toKeep"
276
Note that if your function has parameters, its name will be mangled, so the mangled name should
be used in the keep directive.
Development mode
Running DCE takes a bit of extra time each build, and the output size does not matter during
development. You can improve development builds time by making the DCE tool skip actual dead
code elimination with the dceOptions.devMode ag of the DCE tasks.
For example, to disable DCE based on a custom condition for the main source set and always for
the test code, add the following lines to the build script:
runDceKotlinJs.dceOptions.devMode = isDevMode
runDceTestKotlinJs.dceOptions.devMode = true
Example
A full example that shows how to integrate Kotlin with DCE and webpack to get a small bundle, can
be found here.
Notes
— As for 1.1.x versions, DCE tool is an experimental feature. This does not mean we are going to
remove it, or that it's unusable for production. This means that we can change names of
con guration parameters, default settings, etc.
— Currently you should not use DCE tool if your project is a shared library. It's only applicable
when you are developing an application (which may use shared libraries). The reason is: DCE
does not know which parts of the library are going to be used by the user's application.
— DCE does not perform mini cation (ugli cation) of your code by removing unnecessary
whitespaces and shortening identi ers. You should use existing tools, like UglifyJS
(https://github.com/mishoo/UglifyJS2) or Google Closure Compiler
(https://developers.google.com/closure/compiler/) for this purpose.
277
Native
Concurrency in Kotlin/Native
Kotlin/Native runtime doesn't encourage a classical thread-oriented concurrency model with
mutually exclusive code blocks and conditional variables, as this model is known to be error-prone
and unreliable. Instead, we suggest a collection of alternative approaches, allowing you to use
hardware concurrency and implement blocking IO. Those approaches are as follows, and they will
be elaborated on in further sections:
Workers
Instead of threads Kotlin/Native runtime o ers the concept of workers: concurrently executed
control ow streams with an associated request queue. Workers are very similar to the actors in
the Actor Model. A worker can exchange Kotlin objects with another worker, so that at any moment
each mutable object is owned by a single worker, but ownership can be transferred. See section
Object transfer and freezing.
Once a worker is started with the Worker.start function call, it can be addressed with its own
unique integer worker id. Other workers, or non-worker concurrency primitives, such as OS
threads, can send a message to the worker with the execute call.
278
val future = execute(TransferMode.SAFE, { SomeDataForWorker() }) {
// data returned by the second function argument comes to the
// worker routine as 'input' parameter.
input ->
// Here we create an instance to be returned when someone consumes result future.
WorkerResult(input.stringParam + " result")
}
future.consume {
// Here we see result returned from routine above. Note that future object or
// id could be transferred to another worker, so we don't have to consume future
// in same execution context it was obtained.
result -> println("result is $result")
}
The call to execute uses a function passed as its second parameter to produce an object
subgraph (i.e. set of mutually referring objects) which is then passed as a whole to that worker, it is
then no longer available to the thread that initiated the request. This property is checked if the rst
parameter is TransferMode.SAFE by graph traversal and is just assumed to be true, if it is
TransferMode.UNSAFE . The last parameter to execute is a special Kotlin lambda, which is not
allowed to capture any state, and is actually invoked in the target worker's context. Once
processed, the result is transferred to whatever consumes it in the future, and it is attached to the
object graph of that worker/thread.
If an object is transferred in UNSAFE mode and is still accessible from multiple concurrent
executors, program will likely crash unexpectedly, so consider that last resort in optimizing, not a
general purpose mechanism.
For a more complete example please refer to the workers example in the Kotlin/Native repository.
An important invariant that Kotlin/Native runtime maintains is that the object is either owned by a
single thread/worker, or it is immutable (shared XOR mutable). This ensures that the same data has
a single mutator, and so there is no need for locking to exist. To achieve such an invariant, we use
the concept of not externally referred object subgraphs. This is a subgraph which has no external
references from outside of the subgraph, which could be checked algorithmically with O(N)
complexity (in ARC systems), where N is the number of elements in such a subgraph. Such
subgraphs are usually produced as a result of a lambda expression, for example some builder, and
may not contain objects, referred to externally.
Freezing is a runtime operation making a given object subgraph immutable, by modifying the
object header so that future mutation attempts throw an InvalidMutabilityException . It is
deep, so if an object has a pointer to other objects - transitive closure of such objects will be
frozen. Freezing is a one way transformation, frozen objects cannot be unfrozen. Frozen objects
have a nice property that due to their immutability, they can be freely shared between multiple
workers/threads without breaking the "mutable XOR shared" invariant.
279
If an object is frozen it can be checked with an extension property isFrozen , and if it is, object
sharing is allowed. Currently, Kotlin/Native runtime only freezes the enum objects after creation,
although additional autofreezing of certain provably immutable objects could be implemented in
the future.
Considering the strong ties between Kotlin/Native and C via interoperability, in conjunction with
the other mechanisms mentioned above it is possible to build popular data structures, like
concurrent hashmap or shared cache with Kotlin/Native. It is possible to rely upon shared C data,
and store in it references to detached object subgraphs. Consider the following .def le:
package = global
---
typedef struct {
int version;
void* kotlinObject;
} SharedData;
SharedData sharedData;
After running the cinterop tool it can share Kotlin data in a versionized global structure, and
interact with it from Kotlin transparently via autogenerated Kotlin like this:
So in combination with the top level variable declared above, it can allow looking at the same
memory from di erent threads and building traditional concurrent structures with platform-
speci c synchronization primitives.
280
Frequently, global variables are a source of unintended concurrency issues, so Kotlin/Native
implements the following mechanisms to prevent the unintended sharing of state via global
objects:
— global variables, unless specially marked, can be only accessed from the main thread (that is, the
thread Kotlin/Native runtime was rst initialized), if other thread access such a global,
IncorrectDereferenceException is thrown
— for global variables marked with the @kotlin.native.ThreadLocal annotation each
threads keeps thread-local copy, so changes are not visible between threads
— for global variables marked with the @kotlin.native.SharedImmutable annotation value
is shared, but frozen before publishing, so each threads sees the same value
— singleton objects unless marked with @kotlin.native.ThreadLocal are frozen and shared,
lazy values allowed, unless cyclic frozen structures were attempted to be created
— enums are always frozen
Combined, these mechanisms allow natural race-freeze programming with code reuse across
platforms in MPP projects.
281
Immutability in Kotlin/Native
Kotlin/Native implements strict mutability checks, ensuring the important invariant that the object
is either immutable or accessible from the single thread at that moment in time ( mutable XOR
global ).
To achieve mutable XOR global invariant, all globally visible state (currently, object
singletons and enums) are automatically frozen. If object freezing is not desired, a
kotlin.native.ThreadLocal annotation can be used, which will make the object state thread
local, and so, mutable (but the changed state is not visible to other threads).
Top level/global variables of non-primitive types are by default accessible in the main thread (i.e.,
the thread which initialized Kotlin/Native runtime rst) only. Access from another thread will lead to
an IncorrectDereferenceException being thrown. To make such variables accessible in
other threads, you can use either the @ThreadLocal annotation, and mark the value thread local
or @SharedImmutable , which will make the value frozen and accessible from other threads.
Class AtomicReference can be used to publish the changed frozen state to other threads, and
so build patterns like shared caches.
282
Kotlin/Native libraries
the above command will produce a bar.klib with the compiled contents of foo.kt .
To link to a library use the -library <name> or -l <name> ag. For example:
the above command will produce a program.kexe out of qux.kt and bar.klib
klib utility
The klib library management utility allows you to inspect and install the libraries.
283
All of the above commands accept an additional -repository <directory> argument for
specifying a repository di erent to the default one.
Several examples
First let's create a library. Place the tiny library source code into kotlinizer.kt :
package kotlinizer
val String.kotlinized
get() = "Kotlin $this"
$ ls kotlinizer.klib
kotlinizer.klib
$ rm kotlinizer.klib
import kotlinizer.*
Now compile the program linking with the library we have just created:
$ ./kohello.kexe
Hello, Kotlin world!
Have fun!
Advanced topics
284
When given a -library foo ag, the compiler searches the foo library in the following order:
* Current compilation directory or an absolute path.
* Libraries installed in the default repository (For now the default is `~/.konan`, however
it could be changed by setting **KONAN_DATA_DIR** environment variable).
- foo/
- targets/
- $platform/
- kotlin/
- Kotlin compiled to LLVM bitcode.
- native/
- Bitcode files of additional native objects.
- $another_platform/
- There can be several platform specific kotlin and native pairs.
- linkdata/
- A set of ProtoBuf files with serialized linkage metadata.
- resources/
- General resources such as images. (Not used yet).
- manifest - A file in *java property* format describing the library.
285
Platform libraries
Overview
To provide access to user's native operating system services, Kotlin/Native distribution
includes a set of prebuilt libraries speci c to each target. We call them Platform Libraries.
POSIX bindings
For all Unix or Windows based targets (including Android and iPhone ) we provide the
posix platform lib. It contains bindings to platform's implementation of POSIX standard.
import platform.posix.*
Note that the content of platform.posix is NOT identical on di erent platforms, in the same
way as di erent POSIX implementations are a little di erent.
There are many more platform libraries available for host and cross-compilation targets.
Kotlin/Native distribution provides access to OpenGL , SDL , zlib and other popular native
libraries on applicable platforms.
Availability by default
The packages from platform libraries are available by default. No special link ags need to be
speci ed to use them. Kotlin/Native compiler automatically detects which of the platform
libraries have been accessed and automatically links the needed libraries.
On the other hand, the platform libs in the distribution are merely just wrappers and bindings to
the native libraries. That means the native libraries themselves ( .so , .a , .dylib , .dll etc)
should be installed on the machine.
Examples
Kotlin/Native installation provides a wide spectrum of examples demonstrating the use of
platform libraries. See samples for details.
286
Kotlin/Native interoperability
Introduction
Kotlin/Native follows the general tradition of Kotlin to provide excellent existing platform software
interoperability. In the case of a native platform, the most important interoperability target is a C
library. So Kotlin/Native comes with a cinterop tool, which can be used to quickly generate
everything needed to interact with an external library.
The following work ow is expected when interacting with the native library.
The interoperability tool analyses C headers and produces a "natural" mapping of the types,
functions, and constants into the Kotlin world. The generated stubs can be imported into an IDE for
the purpose of code completion and navigation.
Platform libraries
Note that in many cases there's no need to use custom interoperability library creation
mechanisms described below, as for APIs available on the platform standartized bindings called
platform libraries could be used. For example, POSIX on Linux/macOS platforms, Win32 on
Windows platform, or Apple frameworks on macOS/iOS are available this way.
Simple example
Install libgit2 and prepare stubs for the git library:
cd samples/gitchurn
../../dist/bin/cinterop -def src/main/c_interop/libgit2.def \
-compilerOpts -I/usr/local/include -o libgit2
../../dist/bin/kotlinc src/main/kotlin \
-library libgit2 -o GitChurn
./GitChurn.kexe ../..
287
headers = png.h
headerFilter = png.h
package = png
Then run the cinterop tool with something like this (note that for host libraries that are not
included in the sysroot search paths, headers may be needed):
This command will produce a png.klib compiled library and png-build/kotlin directory
containing Kotlin source code for the library.
If the behavior for a certain platform needs to be modi ed, you can use a format like
compilerOpts.osx or compilerOpts.linux to provide platform-speci c values to the
options.
Note, that the generated bindings are generally platform-speci c, so if you are developing for
multiple targets, the bindings need to be regenerated.
After the generation of bindings, they can be used by the IDE as a proxy view of the native library.
For a typical Unix library with a con g script, the compilerOpts will likely contain the output of a
con g script with the --cflags ag (maybe without exact paths).
The output of a con g script with --libs will be passed as a -linkedArgs kotlinc ag value
(quoted) when compiling.
When library headers are imported to a C program with the #include directive, all of the
headers included by these headers are also included in the program. So all header dependencies
are included in generated stubs as well.
This behavior is correct but it can be very inconvenient for some libraries. So it is possible to
specify in the .def le which of the included headers are to be imported. The separate
declarations from other headers can also be imported in case of direct dependencies.
It is possible to lter headers by globs. The headerFilter property value from the .def le is
treated as a space-separated list of globs. If the included header matches any of the globs, then the
declarations from this header are included into the bindings.
The globs are applied to the header paths relative to the appropriate include path elements, e.g.
time.h or curl/curl.h . So if the library is usually included with #include
<SomeLbrary/Header.h> , then it would probably be correct to lter headers with
headerFilter = SomeLibrary/**
288
If a headerFilter is not speci ed, then all headers are included.
Some libraries have proper module.modulemap or module.map les in its headers. For
example, macOS and iOS system libraries and frameworks do. The module map le describes the
correspondence between header les and modules. When the module maps are available, the
headers from the modules that are not included directly can be ltered out using the experimental
excludeDependentModules option of the .def le:
When both excludeDependentModules and headerFilter are used, they are applied as an
intersection.
Options passed to the C compiler (used to analyze headers, such as preprocessor de nitions) and
the linker (used to link nal executables) can be passed in the de nition le as compilerOpts
and linkerOpts respectively. For example
compilerOpts = -DFOO=bar
linkerOpts = -lpng
Target-speci c options, only applicable to the certain target can be speci ed as well, such as
compilerOpts = -DBAR=bar
compilerOpts.linux_x64 = -DFOO=foo1
compilerOpts.mac_x64 = -DFOO=foo2
and so, C headers on Linux will be analyzed with -DBAR=bar -DFOO=foo1 and on macOS with -
DBAR=bar -DFOO=foo2 . Note that any de nition le option can have both common and the
platform-speci c part.
Sometimes it is required to add custom C declarations to the library before generating bindings
(e.g., for macros). Instead of creating an additional header le with these declarations, you can
include them directly to the end of the .def le, after a separating line, containing only the
separator sequence --- :
headers = errno.h
---
289
Note that this part of the .def le is treated as part of the header le, so functions with the body
should be declared as static . The declarations are parsed after including the les from the
headers list.
Sometimes it is more convenient to ship a static library with your product, rather than assume it is
available within the user's environment. To include a static library into .klib use
staticLibrary and libraryPaths clauses. For example:
staticLibraries = libfoo.a
libraryPaths = /opt/local/lib /usr/local/opt/curl/lib
When given the above snippet the cinterop tool will search libfoo.a in /opt/local/lib
and /usr/local/opt/curl/lib , and if it is found include the library binary into klib .
When using such klib in your program, the library is linked automatically.
Using bindings
— Signed, unsigned integral, and oating point types are mapped to their Kotlin counterpart with
the same width.
— Pointers and arrays are mapped to CPointer<T>? .
— Enums can be mapped to either Kotlin enum or integral values, depending on heuristics and the
de nition le hints.
— Structs are mapped to types having elds available via the dot notation, i.e.
someStructInstance.field1 .
— typedef are represented as typealias .
Also, any C type has the Kotlin type representing the lvalue of this type, i.e., the value located in
memory rather than a simple immutable self-contained value. Think C++ references, as a similar
concept. For structs (and typedef s to structs) this representation is the main one and has the
same name as the struct itself, for Kotlin enums it is named ${type}Var , for CPointer<T> it is
CPointerVar<T> , and for most other types it is ${type}Var .
For types that have both representations, the one with a "lvalue" has a mutable .value property
for accessing the value.
Pointer types
290
The type argument T of CPointer<T> must be one of the "lvalue" types described above, e.g.,
the C type struct S* is mapped to CPointer<S> , int8_t* is mapped to
CPointer<int_8tVar> , and char** is mapped to CPointer<CPointerVar<ByteVar>> .
C null pointer is represented as Kotlin's null , and the pointer type CPointer<T> is not nullable,
but the CPointer<T>? is. The values of this type support all the Kotlin operations related to
handling null , e.g. ?: , ?. , !! etc.:
Since the arrays are also mapped to CPointer<T> , it supports the [] operator for accessing
values by index:
The .pointed property for CPointer<T> returns the lvalue of type T , pointed by this pointer.
The reverse operation is .ptr : it takes the lvalue and returns the pointer to it.
void* is mapped to COpaquePointer – the special pointer type which is the supertype for any
other pointer type. So if the C function takes void* , then the Kotlin binding accepts any
CPointer .
or
As is with C, these reinterpret casts are unsafe and can potentially lead to subtle memory problems
in the application.
Also there are unsafe casts between CPointer<T>? and Long available, provided by the
.toLong() and .toCPointer<T>() extension methods:
Note that if the type of the result is known from the context, the type argument can be omitted as
usual due to the type inference.
Memory allocation
The native memory can be allocated using the NativePlacement interface, e.g.
291
val byteVar = placement.alloc<ByteVar>()
or
The most "natural" placement is in the object nativeHeap . It corresponds to allocating native
memory with malloc and provides an additional .free() operation to free allocated memory:
However, the lifetime of allocated memory is often bound to the lexical scope. It is possible to
de ne such scope with memScoped { ... } . Inside the braces, the temporary placement is
available as an implicit receiver, so it is possible to allocate native memory with alloc and
allocArray , and the allocated memory will be automatically freed after leaving the scope.
For example, the C function returning values through pointer parameters can be used like
Although C pointers are mapped to the CPointer<T> type, the C function pointer-typed
parameters are mapped to CValuesRef<T> . When passing CPointer<T> as the value of such a
parameter, it is passed to the C function as is. However, the sequence of values can be passed
instead of a pointer. In this case the sequence is passed "by value", i.e., the C function receives the
pointer to the temporary copy of that sequence, which is valid only until the function returns.
— Array<CPointer<T>?>.toCValues() , List<CPointer<T>?>.toCValues()
For example:
C:
292
Kotlin:
foo(cValuesOf(1, 2, 3), 3)
Unlike other pointers, the parameters of type const char* are represented as a Kotlin String .
So it is possible to pass any Kotlin string to a binding expecting a C string.
There are also some tools available to convert between Kotlin and C strings manually:
To skip automatic conversion and ensure raw pointers are used in the bindings, a
noStringConversion statement in the .def le could be used, i.e.
This way any value of type CPointer<ByteVar> can be passed as an argument of const char*
type. If a Kotlin string should be passed, code like this could be used:
memScoped {
LoadCursorA(null, "cursor.bmp".cstr.ptr) // for ASCII version
LoadCursorW(null, "cursor.bmp".wcstr.ptr) // for Unicode version
}
Scope-local pointers
memScoped {
items = arrayOfNulls<CPointer<ITEM>?>(6)
arrayOf("one", "two").forEachIndexed { index, value -> items[index] = value.cstr.ptr }
menu = new_menu("Menu".cstr.ptr, items.toCValues().ptr)
...
}
In this example, all values passed to the C API new_menu() have a lifetime of the innermost
memScope it belongs to. Once the control ow leaves the memScoped scope the C pointers
become invalid.
293
Passing and receiving structs by value
When a C function takes or returns a struct T by value, the corresponding argument type or return
type is represented as CValue<T> .
CValue<T> is an opaque type, so the structure elds cannot be accessed with the appropriate
Kotlin properties. It should be possible, if an API uses structures as handles, but if eld access is
required, there are the following conversion methods available:
Callbacks
Note that some function types are not supported currently. For example, it is not possible to get a
pointer to a function that receives or returns structs by value.
If the callback doesn't run in the main thread, it is mandatory to init the Kotlin/Native runtime by
calling kotlin.native.initRuntimeIfNeeded() .
Often C APIs allow passing some user data to callbacks. Such data is usually provided by the user
when con guring the callback. It is passed to some C function (or written to the struct) as e.g.
void* . However, references to Kotlin objects can't be directly passed to C. So they require
wrapping before con guring the callback and then unwrapping in the callback itself, to safely swim
from Kotlin to Kotlin through the C world. Such wrapping is possible with StableRef class.
294
where kotlinReference is the original wrapped reference.
The created StableRef should eventually be manually disposed using the .dispose() method
to prevent memory leaks:
stableRef.dispose()
Macros
Every C macro that expands to a constant is represented as a Kotlin property. Other macros are not
supported. However, they can be exposed manually by wrapping them with supported
declarations. E.g. function-like macro FOO can be exposed as function foo by adding the custom
declaration to the library:
headers = library/base.h
---
De nition le hints
The .def le supports several options for adjusting the generated bindings.
Portability
Sometimes the C libraries have function parameters or struct elds of a platform-dependent type,
e.g. long or size_t . Kotlin itself doesn't provide neither implicit integer casts nor C-style integer
casts (e.g. (size_t) intValue ), so to make writing portable code in such cases easier, the
convert method is provided:
295
fun ${type1}.convert<${type2}>(): ${type2}
where each of type1 and type2 must be an integral type, either signed or unsigned.
.convert<${type}> has the same semantics as one of the .toByte , .toShort , .toInt ,
.toLong , .toUByte , .toUShort , .toUInt or .toULong methods, depending on type .
Also, the type parameter can be inferred automatically and so may be omitted in some cases.
Object pinning
Kotlin objects could be pinned, i.e. their position in memory is guaranteed to be stable until
unpinned, and pointers to such objects inner data could be passed to the C functions. For example
if (length <= 0) {
break
}
// Now `buffer` has raw data obtained from the `recv()` call.
}
}
}
Here we use service function usePinned , which pins an object, executes block and unpins it on
normal and exception paths.
296
Kotlin/Native interoperability with Swift/Objective-C
This document covers some details of Kotlin/Native interoperability with Swift/Objective-C.
Usage
Kotlin/Native provides bidirectional interoperability with Objective-C. Objective-C frameworks and
libraries can be used in Kotlin code if properly imported to the build (system frameworks are
imported by default). See e.g. "Using cinterop" in Gradle plugin documentation. A Swift library can
be used in Kotlin code if its API is exported to Objective-C with @objc . Pure Swift modules are not
yet supported.
Kotlin modules can be used in Swift/Objective-C code if compiled into a framework (see "Targets
and output kinds" section in Gradle plugin documentation). See calculator sample for an example.
Mappings
The table below shows how Kotlin concepts are mapped to Swift/Objective-C and vice versa.
Name translation
Objective-C classes are imported into Kotlin with their original names. Protocols are imported as
interfaces with Protocol name su x, i.e. @protocol Foo -> interface FooProtocol .
These classes and interfaces are placed into a package speci ed in build con guration
( platform.* packages for precon gured system frameworks).
297
The names of Kotlin classes and interfaces are pre xed when imported to Objective-C. The pre x is
derived from the framework name.
Initializers
Swift/Objective-C initializers are imported to Kotlin as constructors and factory methods named
create . The latter happens with initializers declared in the Objective-C category or as a Swift
extension, because Kotlin has no concept of extension constructors.
Top-level Kotlin functions and properties are accessible as members of special classes. Each Kotlin
le is translated into such a class. E.g.
// MyLibraryUtils.kt
package my.library
fun foo() {}
MyLibraryUtilsKt.foo()
Generally Swift argument labels and Objective-C selector pieces are mapped to Kotlin parameter
names. Anyway these two concepts have di erent semantics, so sometimes Swift/Objective-C
methods can be imported with a clashing Kotlin signature. In this case the clashing methods can be
called from Kotlin using named arguments, e.g.:
Kotlin has no concept of checked exceptions, all Kotlin exceptions are unchecked. Swift has only
checked errors. So if Swift or Objective-C code calls a Kotlin method which throws an exception to
be handled, then the Kotlin method should be marked with a @Throws annotation. In this case all
Kotlin exceptions (except for instances of Error , RuntimeException and subclasses) are
translated into a Swift error/ NSError .
298
Note that the opposite reversed translation is not implemented yet: Swift/Objective-C error-
throwing methods aren't imported to Kotlin as exception-throwing.
Category members
Members of Objective-C categories and Swift extensions are imported to Kotlin as extensions.
That's why these declarations can't be overridden in Kotlin. And the extension initializers aren't
available as Kotlin constructors.
Kotlin singletons
Kotlin singleton (made with an object declaration, including companion object ) is imported
to Swift/Objective-C as a class with a single instance. The instance is available through the factory
method, i.e. as [MySingleton mySingleton] in Objective-C and MySingleton() in Swift.
NSNumber
Kotlin primitive type boxes are mapped to special Swift/Objective-C classes. For example,
kotlin.Int box is represented as KotlinInt class instance in Swift (or ${prefix}Int
instance in Objective-C, where prefix is the framework names pre x). These classes are derived
from NSNumber , so the instances are proper NSNumber s supporting all corresponding
operations.
NSNumber type is not automatically translated to Kotlin primitive types when used as a
Swift/Objective-C parameter type or return value. The reason is that NSNumber type doesn't
provide enough information about a wrapped primitive value type, i.e. NSNumber is statically not
known to be a e.g. Byte , Boolean , or Double . So Kotlin primitive values should be cast to/from
NSNumber manually (see below).
NSMutableString
Collections
Kotlin collections are converted to Swift/Objective-C collections as described in the table above.
Swift/Objective-C collections are mapped to Kotlin in the same way, except for NSMutableSet
and NSMutableDictionary . NSMutableSet isn't converted to a Kotlin MutableSet . To pass
an object for Kotlin MutableSet , you can create this kind of Kotlin collection explicitly by either
creating it in Kotlin with e.g. mutableSetOf() , or using the KotlinMutableSet class in Swift
(or ${prefix}MutableSet in Objective-C, where prefix is the framework names pre x). The
same holds for MutableMap .
299
Function types
Kotlin function-typed objects (e.g. lambdas) are converted to Swift functions / Objective-C blocks.
However there is a di erence in how types of parameters and return values are mapped when
translating a function and a function type. In the latter case primitive types are mapped to their
boxed representation. Kotlin Unit return value is represented as a corresponding Unit
singleton in Swift/Objective-C. The value of this singleton can be retrieved in the same way as it is
for any other Kotlin object (see singletons in the table above). To sum the things up:
foo {
bar($0 as! Int32)
return KotlinUnit()
}
Subclassing
Kotlin classes and interfaces can be subclassed by Swift/Objective-C classes and protocols.
Currently a class that adopts the Kotlin protocol should inherit NSObject (either directly or
indirectly). Note that all Kotlin classes do inherit NSObject , so a Swift/Objective-C subclass of
Kotlin class can adopt the Kotlin protocol.
Swift/Objective-C classes and protocols can be subclassed with a Kotlin final class. Non- final
Kotlin classes inheriting Swift/Objective-C types aren't supported yet, so it is not possible to declare
a complex class hierarchy inheriting Swift/Objective-C types.
Normal methods can be overridden using the override Kotlin keyword. In this case the
overriding method must have the same parameter names as the overridden one.
300
Sometimes it is required to override initializers, e.g. when subclassing UIViewController .
Initializers imported as Kotlin constructors can be overridden by Kotlin constructors marked with
the @OverrideInit annotation:
...
}
The overriding constructor must have the same parameter names and types as the overridden one.
To override di erent methods with clashing Kotlin signatures, you can add a
@Suppress("CONFLICTING_OVERLOADS") annotation to the class.
By default the Kotlin/Native compiler doesn't allow calling a non-designated Objective-C initializer
as a super(...) constructor. This behaviour can be inconvenient if the designated initializers
aren't marked properly in the Objective-C library. Adding a
disableDesignatedInitializerChecks = true to the .def le for this library would
disable these compiler checks.
C features
See INTEROP.md for an example case where the library uses some plain C features (e.g. unsafe
pointers, structs etc.).
301
Kotlin/Native Gradle plugin
IMPORTANT NOTICE
This document describes Kotlin/Native experimental Gradle plugin, which is not the plugin yet
supported by IDE or in multiplatform projects. See MPP Gradle plugin documentation for more
information.
Overview
You may use the Gradle plugin to build Kotlin/Native projects. Builds of the plugin are available at
the Gradle plugin portal, so you can apply it using Gradle plugin DSL:
plugins {
id "org.jetbrains.kotlin.platform.native" version "1.3.0-rc-146"
}
You also can get the plugin from a Bintray repository. In addition to releases, this repo contains old
and development versions of the plugin which are not available at the plugin portal. To get the
plugin from the Bintray repo, include the following snippet in your build script:
buildscript {
repositories {
mavenCentral()
maven {
url "https://dl.bintray.com/jetbrains/kotlin-native-dependencies"
}
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-native-gradle-plugin:1.3.0-rc-146"
}
}
By default the plugin downloads the Kotlin/Native compiler during the rst run. If you have already
downloaded the compiler manually you can specify the path to its root directory using
konan.home project property (e.g. in gradle.properties ).
konan.home=/home/user/kotlin-native-0.8
Source management
302
By default the production sources are located in src/main/kotlin and the test sources - in
src/test/kotlin .
sourceSets {
// Adding target-independent sources.
main.kotlin.srcDirs += 'src/main/mySources'
By default the plugin creates software components for the main and test source sets. You can
access them via the components container provided by Gradle or via the component property
of a corresponding source set:
// Main component.
components.main
sourceSets.main.component
// Test component.
components.test
sourceSets.test.component
components.main {
// Compile this component for 64-bit MacOS, Linux and Windows.
targets = ['macos_x64', 'linux_x64', 'mingw_x64']
}
The plugin uses the same notation as the compiler. By default, test component uses the same
targets as speci ed for the main one.
components.main {
// Compile the component into an executable and a Kotlin/Native library.
outputKinds = [EXECUTABLE, KLIBRARY]
}
All constants used here are available inside a component con guration script block. The plugin
supports producing binaries of the following kinds:
303
— FRAMEWORK - an Objective-C framework;
Also each native binary is built in two variants (build types): debug (debuggable, not optimized)
and release (not debuggable, optimized). Note that Kotlin/Native libraries have only debug
variant because optimizations are preformed only during compilation of a nal binary (executable,
static lib etc) and a ect all libraries used to build it.
Compile tasks
The plugin creates a compilation task for each combination of the target, output kind, and build
type. The tasks have the following naming convention:
compile<ComponentName><BuildType><OutputKind><Target>KotlinNative
The name contains the following parts (some of them may be empty):
— <OutputKind> - output kind name, e.g. Executabe or Dynamic . Empty if the component
has only one output kind.
— <Target> - target the component is built for, e.g. Macos_x64 or Wasm32 . Empty if the
component is built only for one target.
Also the plugin creates a number of aggregate tasks allowing you to build all the binaries for a build
type (e.g. assembleAllDebug ) or all the binaries for a particular target (e.g.
assembleAllWasm32 ).
Basic lifecycle tasks like assemble , build , and clean are also available.
Running tests
The plugin builds a test executable for all the targets speci ed for the test component. If the
current host platform is included in this list the test running tasks are also created. To run tests,
execute the standard lifecycle check task:
./gradlew check
Dependencies
304
The plugin allows you to declare dependencies on les and other projects using traditional Gradle's
mechanism of con gurations. The plugin supports Kotlin multiplatform projects allowing you to
declare the expectedBy dependencies
dependencies {
implementation files('path/to/file/dependencies')
implementation project('library')
testImplementation project('testLibrary')
expectedBy project('common')
}
It's possible to depend on a Kotlin/Native library published earlier in a maven repo. The plugin
relies on Gradle's metadata support so the corresponding feature must be enabled. Add the
following line in your settings.gradle :
enableFeaturePreview('GRADLE_METADATA')
dependencies {
implementation 'org.sample.test:mylibrary:1.0'
testImplementation 'org.sample.test:testlibrary:1.0'
}
components.main {
dependencies {
implementation 'org.sample.test:mylibrary:1.0'
}
}
components.test {
dependencies {
implementation 'org.sample.test:testlibrary:1.0'
}
}
Using cinterop
305
components.main {
dependencies {
cinterop('mystdio') {
// src/main/c_interop/mystdio.def is used as a def file.
Here an interop library will be built and added in the component dependencies.
Often it's necessary to specify target-speci c linker options for a Kotlin/Native binary using an
interop. It can be done using the target script block:
components.main {
target('linux') {
linkerOpts '-L/path/to/linux/libs'
}
}
components.main {
// Configure all targets.
allTargets {
linkerOpts '-L/path/to/libs'
}
}
Publishing
In the presence of maven-publish plugin the publications for all the binaries built are created.
The plugin uses Gradle metadata to publish the artifacts so this feature must be enabled (see the
dependencies section).
Now you can publish the artifacts with the standard Gradle publish task:
./gradlew publish
The plugin allows you to customize the pom generated for the publication with the pom code
block available for every component:
306
components.main {
pom {
withXml {
def root = asNode()
root.appendNode('name', 'My library')
root.appendNode('description', 'A Kotlin/Native library')
}
}
}
Serialization plugin
The plugin is shipped with a customized version of the kotlinx.serialization plugin. To use
it you don't have to add new buildscript dependencies, just apply the plugins and add a
dependency on the serialization library:
dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-runtime-native'
}
DSL example
In this section a commented DSL is shown. See also the example projects that use this plugin, e.g.
Kotlinx.coroutines, MPP http client
plugins {
id "org.jetbrains.kotlin.platform.native" version "1.3.0-rc-146"
}
sourceSets.main {
// Plugin uses Gradle's source directory sets here,
// so all the DSL methods available in SourceDirectorySet can be called here.
// Platform independent sources.
kotlin.srcDirs += 'src/main/customDir'
// Linux-specific sources
target('linux').srcDirs += 'src/main/linux'
}
components.main {
// Set up targets
targets = ['linux_x64', 'macos_x64', 'mingw_x64']
// Target-specific options
target('linux_x64') {
linkerOpts '-L/linux/lib/path'
307
linkerOpts '-L/linux/lib/path'
}
dependencies {
// Dependency on a project
implementation project('library')
// Cinterop dependency
cinterop('interop-name') {
// Def-file describing the native API.
// The default path is src/main/c_interop/<interop-name>.def
defFile project.file("deffile.def")
308
def root = asNode()
root.appendNode('name', 'My library')
root.appendNode('description', 'A Kotlin/Native library')
}
}
309
Debugging
Currently the Kotlin/Native compiler produces debug info compatible with the DWARF 2
speci cation, so modern debugger tools can perform the following operations:
— breakpoints
— stepping
— inspection of type information
— variable inspection
To produce binaries with the Kotlin/Native compiler it's su cient to use the -g option on the
command line.
Example:
Breakpoints
310
Modern debuggers provide several ways to set a breakpoint, see below for a tool-by-tool
breakdown:
lldb
— by name
(lldb) b -n kfun:main(kotlin.Array<kotlin.String>)
Breakpoint 4: where = terminator.kexe`kfun:main(kotlin.Array<kotlin.String>) + 4 at
hello.kt:2, address = 0x00000001000012e4
(lldb) b -f hello.kt -l 1
Breakpoint 1: where = terminator.kexe`kfun:main(kotlin.Array<kotlin.String>) + 4 at
hello.kt:2, address = 0x00000001000012e4
— by address
(lldb) b -a 0x00000001000012e4
Breakpoint 2: address = 0x00000001000012e4
— by regex, you might nd it useful for debugging generated artifacts, like lambda etc. (where
used # symbol in name).
gdb
— by regex
(gdb) b kfun:main(kotlin.Array<kotlin.String>)
No source file named kfun.
Make breakpoint pending on future shared library load? (y or [n]) y
Breakpoint 1 (kfun:main(kotlin.Array<kotlin.String>)) pending
— by location
(gdb) b hello.kt:1
Breakpoint 2 at 0x100001704: file /Users/minamoto/ws/.git-trees/hello.kt, line 1.
— by address
311
(gdb) b *0x100001704
Note: breakpoint 2 also set at pc 0x100001704.
Breakpoint 3 at 0x100001704: file /Users/minamoto/ws/.git-trees/hello.kt, line 2.
Stepping
Stepping functions works mostly the same way as for C/C++ programs
Variable inspection
Variable inspections for var variables works out of the box for primitive types. For non-primitive
types there are custom pretty printers for lldb in konan_lldb.py :
λ cat main.kt | nl
1 fun main(args: Array<String>) {
2 var x = 1
3 var y = 2
4 var p = Point(x, y)
5 println("p = $p")
6 }
312
Getting representation of the object variable (var) could also be done using the built-in runtime
function Konan_DebugPrint (this approach also works for gdb, using a module of command
syntax):
Known issues
Note: Supporting the DWARF 2 speci cation means that the debugger tool recognizes Kotlin as C89,
because before the DWARF 5 speci cation, there is no identi er for the Kotlin language type in
speci cation.
313
Q: How do I run my program?
A: De ne a top level function fun main(args: Array<String>) or just fun main() if you
are not interested in passed arguments, please ensure it's not in a package. Also compiler switch -
entry could be used to make any function taking Array<String> or no arguments and return
Unit as an entry point.
A: Kotlin/Native provides an automated memory management scheme, similar to what Java or Swift
provides. The current implementation includes an automated reference counter with a cycle
collector to collect cyclical garbage.
targets {
fromPreset(presets.iosArm64, 'mylib') {
compilations.main.outputKinds 'DYNAMIC'
}
}
It will produce a platform-speci c shared object (.so on Linux, .dylib on macOS, and .dll on Windows
targets) and a C language header, allowing the use of all public APIs available in your Kotlin/Native
program from C/C++ code. See samples/python_extension for an example of using such a
shared object to provide a bridge between Python and Kotlin/Native.
targets {
fromPreset(presets.iosArm64, 'mylib') {
compilations.main.outputKinds 'STATIC'
}
}
It will produce a platform-speci c static object (.a library format) and a C language header, allowing
you to use all the public APIs available in your Kotlin/Native program from C/C++ code.
314
A: As Kotlin/Native needs to download a platform speci c toolchain, you need to specify -
Dhttp.proxyHost=xxx -Dhttp.proxyPort=xxx as the compiler's or gradlew arguments, or
set it via the JAVA_OPTS environment variable.
A: Use the -module_name compiler option or matching Gradle DSL statement, i.e.
targets {
fromPreset(presets.iosArm64, 'myapp') {
compilations.main.outputKinds 'FRAMEWORK'
compilations.main.extraOpts '-module_name', 'TheName'
}
}
targets {
fromPreset(presets.iosArm64, 'myapp') {
compilations.main.outputKinds 'FRAMEWORK'
compilations.main.extraOpts '-Xembed-bitcode' // for release binaries
// or '-Xembed-bitcode-marker' for debug binaries
}
These options have nearly the same e ect as clang's -fembed-bitcode / -fembed-bitcode-
marker and swiftc's -embed-bitcode / -embed-bitcode-marker .
A: It likely happens, because you are trying to mutate a frozen object. An object can transfer to the
frozen state either explicitly, as objects reachable from objects on which the
kotlin.native.concurrent.freeze is called, or implicitly (i.e. reachable from enum or
global singleton object - see the next question).
A: Currently, singleton objects are immutable (i.e. frozen after creation), and it's generally
considered good practise to have the global state immutable. If for some reason you need a
mutable state inside such an object, use the @konan.ThreadLocal annotation on the object.
Also the kotlin.native.concurrent.AtomicReference class could be used to store
di erent pointers to frozen objects in a frozen object and automatically update them.
315
A: We release dev builds frequently, usually at least once a week. You can check the list of available
versions. But if we recently xed an issue and you want to check it before a release is done, you
can do:
For the CLI, you can compile using gradle as stated in the README (and if you get errors, you can try to do a
./gradlew clean):
For Gradle, you can use Gradle composite builds like this:
316
Coroutines
Kotlin, as a language, provides only minimal low-level APIs in its standard library to enable various
other libraries to utilize coroutines. Unlike many other languages with similar capabilities, async
and await are not keywords in Kotlin and are not even part of its standard library. Moreover,
Kotlin's concept of suspending function provides a safer and less error-prone abstraction for
asynchronous operations than futures and promises.
In order to use coroutines as well as follow the examples in this guide, you need to add a
dependency on kotlinx-coroutines-core module as explained in the project README .
Table of contents
— Coroutine basics
— Cancellation and timeouts
— Composing suspending functions
— Coroutine context and dispatchers
— Exception handling and supervision
— Channels (experimental)
— Shared mutable state and concurrency
— Select expression (experimental)
Additional references
— Guide to UI programming with coroutines
Guide to reactive streams with coroutines
—
— Coroutines design document (KEEP)
— Full kotlinx.coroutines API reference
317
Table of contents
— Coroutine basics
— Your rst coroutine
— Bridging blocking and non-blocking worlds
— Waiting for a job
— Structured concurrency
— Scope builder
— Extract function refactoring
— Coroutines ARE light-weight
— Global coroutines are like daemon threads
Coroutine basics
This section covers basic coroutine concepts.
import kotlinx.coroutines.*
fun main() {
GlobalScope.launch { // launch new coroutine in background and continue
delay(1000L) // non-blocking delay for 1 second (default time unit is ms)
println("World!") // print after delay
}
println("Hello,") // main thread continues while coroutine is delayed
Thread.sleep(2000L) // block main thread for 2 seconds to keep JVM alive
}
Hello,
World!
Essentially, coroutines are light-weight threads. They are launched with launch coroutine builder in a
context of some CoroutineScope. Here we are launching a new coroutine in the GlobalScope,
meaning that the lifetime of the new coroutine is limited only by the lifetime of the whole
application.
You can achieve the same result replacing GlobalScope.launch { ... } with thread { ...
} and delay(...) with Thread.sleep(...) . Try it.
318
If you start by replacing GlobalScope.launch by thread , the compiler produces the following
error:
Error: Kotlin: Suspend functions are only allowed to be called from a coroutine or another
suspend function
That is because delay is a special suspending function that does not block a thread, but suspends
coroutine and it can be only used from a coroutine.
The rst example mixes non-blocking delay(...) and blocking Thread.sleep(...) in the
same code. It is easy to lose track of which one is blocking and which one is not. Let's be explicit
about blocking using runBlocking coroutine builder:
import kotlinx.coroutines.*
fun main() {
GlobalScope.launch { // launch new coroutine in background and continue
delay(1000L)
println("World!")
}
println("Hello,") // main thread continues here immediately
runBlocking { // but this expression blocks the main thread
delay(2000L) // ... while we delay for 2 seconds to keep JVM alive
}
}
The result is the same, but this code uses only non-blocking delay. The main thread, that invokes
runBlocking , blocks until the coroutine inside runBlocking completes.
This example can be also rewritten in a more idiomatic way, using runBlocking to wrap the
execution of the main function:
import kotlinx.coroutines.*
Here runBlocking<Unit> { ... } works as an adaptor that is used to start the top-level main
coroutine. We explicitly specify its Unit return type, because a well-formed main function in
Kotlin has to return Unit .
319
This is also a way to write unit-tests for suspending functions:
class MyTest {
@Test
fun testMySuspendingFunction() = runBlocking<Unit> {
// here we can use suspending functions using any assertion style that we like
}
}
Delaying for a time while another coroutine is working is not a good approach. Let's explicitly wait
(in a non-blocking way) until the background Job that we have launched is complete:
val job = GlobalScope.launch { // launch new coroutine and keep a reference to its Job
delay(1000L)
println("World!")
}
println("Hello,")
job.join() // wait until child coroutine completes
Now the result is still the same, but the code of the main coroutine is not tied to the duration of
the background job in any way. Much better.
Structured concurrency
There is still something to be desired for practical usage of coroutines. When we use
GlobalScope.launch we create a top-level coroutine. Even though it is light-weight, it still
consumes some memory resources while it runs. If we forget to keep a reference to the newly
launched coroutine it still runs. What if the code in the coroutine hangs (for example, we
erroneously delay for too long), what if we launched too many coroutines and ran out of memory?
Having to manually keep a reference to all the launched coroutines and join them is error-prone.
There is a better solution. We can use structured concurrency in our code. Instead of launching
coroutines in the GlobalScope, just like we usually do with threads (threads are always global), we
can launch coroutines in the speci c scope of the operation we are performing.
In our example, we have main function that is turned into a coroutine using runBlocking
coroutine builder. Every coroutine builder, including runBlocking , adds an instance of
CoroutineScope to the scope of its code block. We can launch coroutines in this scope without
having to join them explicitly, because an outer coroutine ( runBlocking in our example) does
not complete until all the coroutines launched in its scope complete. Thus, we can make our
example simpler:
320
import kotlinx.coroutines.*
Scope builder
In addition to the coroutine scope provided by di erent builders, it is possible to declare your own
scope using coroutineScope builder. It creates new coroutine scope and does not complete until all
launched children complete. The main di erence between runBlocking and coroutineScope is that
the latter does not block the current thread while waiting for all children to complete.
import kotlinx.coroutines.*
delay(100L)
println("Task from coroutine scope") // This line will be printed before nested
launch
}
println("Coroutine scope is over") // This line is not printed until nested launch
completes
}
Let's extract the block of code inside launch { ... } into a separate function. When you
perform "Extract function" refactoring on this code you get a new function with suspend modi er.
That is your rst suspending function. Suspending functions can be used inside coroutines just like
regular functions, but their additional feature is that they can, in turn, use other suspending
functions, like delay in this example, to suspend execution of a coroutine.
321
import kotlinx.coroutines.*
But what if the extracted function contains a coroutine builder which is invoked on the current
scope? In this case suspend modi er on the extracted function is not enough. Making doWorld
extension method on CoroutineScope is one of the solutions, but it may not always be
applicable as it does not make API clearer. Idiomatic solution is to have either explicit
CoroutineScope as a eld in a class containing target function or implicit when outer class
implements CoroutineScope . As a last resort, CoroutineScope(coroutineContext) can be used,
but such approach is structurally unsafe because you no longer have control on the scope this
method is executed. Only private API can use this builder.
import kotlinx.coroutines.*
It launches 100K coroutines and, after a second, each coroutine prints a dot. Now, try that with
threads. What would happen? (Most likely your code will produce some sort of out-of-memory
error)
The following code launches a long-running coroutine in GlobalScope that prints "I'm sleeping"
twice a second and then returns from the main function after some delay:
322
GlobalScope.launch {
repeat(1000) { i ->
println("I'm sleeping $i ...")
delay(500L)
}
}
delay(1300L) // just quit after delay
You can run and see that it prints three lines and terminates:
Active coroutines that were launched in GlobalScope do not keep the process alive. They are like
daemon threads.
323
Table of contents
In a long-running application you might need ne-grained control on your background coroutines.
For example, a user might have closed the page that launched a coroutine and now its result is no
longer needed and its operation can be cancelled. The launch function returns a Job that can be
used to cancel running coroutine:
As soon as main invokes job.cancel , we don't see any output from the other coroutine because
it was cancelled. There is also a Job extension function cancelAndJoin that combines cancel and join
invocations.
Cancellation is cooperative
324
Coroutine cancellation is cooperative. A coroutine code has to cooperate to be cancellable. All the
suspending functions in kotlinx.coroutines are cancellable. They check for cancellation of
coroutine and throw CancellationException when cancelled. However, if a coroutine is working in a
computation and does not check for cancellation, then it cannot be cancelled, like the following
example shows:
Run it to see that it continues to print "I'm sleeping" even after cancellation until the job completes
by itself after ve iterations.
There are two approaches to making computation code cancellable. The rst one is to periodically
invoke a suspending function that checks for cancellation. There is a yield function that is a good
choice for that purpose. The other one is to explicitly check the cancellation status. Let us try the
latter approach.
Replace while (i < 5) in the previous example with while (isActive) and rerun it.
325
You can get full code here
As you can see, now this loop is cancelled. isActive is an extension property that is available inside
the code of coroutine via CoroutineScope object.
Both join and cancelAndJoin wait for all the nalization actions to complete, so the example above
produces the following output:
Any attempt to use a suspending function in the finally block of the previous example causes
CancellationException, because the coroutine running this code is cancelled. Usually, this is not a
problem, since all well-behaving closing operations (closing a le, cancelling a job, or closing any
kind of a communication channel) are usually non-blocking and do not involve any suspending
functions. However, in the rare case when you need to suspend in the cancelled coroutine you can
wrap the corresponding code in withContext(NonCancellable) {...} using withContext
function and NonCancellable context as the following example shows:
326
val job = launch {
try {
repeat(1000) { i ->
println("I'm sleeping $i ...")
delay(500L)
}
} finally {
withContext(NonCancellable) {
println("I'm running finally")
delay(1000L)
println("And I've just delayed for 1 sec because I'm non-cancellable")
}
}
}
delay(1300L) // delay a bit
println("main: I'm tired of waiting!")
job.cancelAndJoin() // cancels the job and waits for its completion
println("main: Now I can quit.")
Timeout
The most obvious reason to cancel coroutine execution in practice is because its execution time
has exceeded some timeout. While you can manually track the reference to the corresponding Job
and launch a separate coroutine to cancel the tracked one after delay, there is a ready to use
withTimeout function that does it. Look at the following example:
withTimeout(1300L) {
repeat(1000) { i ->
println("I'm sleeping $i ...")
delay(500L)
}
}
327
Because cancellation is just an exception, all the resources are closed in a usual way. You can wrap
the code with timeout in try {...} catch (e: TimeoutCancellationException) {...}
block if you need to do some additional action speci cally on any kind of timeout or use
withTimeoutOrNull function that is similar to withTimeout, but returns null on timeout instead of
throwing an exception:
328
Table of contents
— Channels (experimental)
— Channel basics
— Closing and iteration over channels
— Building channel producers
— Pipelines
— Prime numbers with pipeline
— Fan-out
— Fan-in
— Bu ered channels
— Channels are fair
— Ticker channels
Channels (experimental)
Deferred values provide a convenient way to transfer a single value between coroutines. Channels
provide a way to transfer a stream of values.
Channel basics
A Channel is conceptually very similar to BlockingQueue . One key di erence is that instead of a
blocking put operation it has a suspending send, and instead of a blocking take operation it has
a suspending receive.
329
1
4
9
16
25
Done!
Unlike a queue, a channel can be closed to indicate that no more elements are coming. On the
receiver side it is convenient to use a regular for loop to receive elements from the channel.
Conceptually, a close is like sending a special close token to the channel. The iteration stops as
soon as this close token is received, so there is a guarantee that all previously sent elements before
the close are received:
The pattern where a coroutine is producing a sequence of elements is quite common. This is a part
of producer-consumer pattern that is often found in concurrent code. You could abstract such a
producer into a function that takes channel as its parameter, but this goes contrary to common
sense that results must be returned from functions.
There is a convenient coroutine builder named produce that makes it easy to do it right on
producer side, and an extension function consumeEach, that replaces a for loop on the
consumer side:
Pipelines
A pipeline is a pattern where one coroutine is producing, possibly in nite, stream of values:
330
fun CoroutineScope.produceNumbers() = produce<Int> {
var x = 1
while (true) send(x++) // infinite stream of integers starting from 1
}
And another coroutine or coroutines are consuming that stream, doing some processing, and
producing some other results. In the example below, the numbers are just squared:
All functions that create coroutines are de ned as extensions on CoroutineScope, so that we
can rely on structured concurrency to make sure that we don't have lingering global coroutines
in our application.
Let's take pipelines to the extreme with an example that generates prime numbers using a pipeline
of coroutines. We start with an in nite sequence of numbers.
The following pipeline stage lters an incoming stream of numbers, removing all the numbers that
are divisible by the given prime number:
Now we build our pipeline by starting a stream of numbers from 2, taking a prime number from
the current channel, and launching new pipeline stage for each prime number found:
numbersFrom(2) -> filter(2) -> filter(3) -> filter(5) -> filter(7) ...
331
The following example prints the rst ten prime numbers, running the whole pipeline in the
context of the main thread. Since all the coroutines are launched in the scope of the main
runBlocking coroutine we don't have to keep an explicit list of all the coroutines we have started.
We use cancelChildren extension function to cancel all the children coroutines after we have
printed the rst ten prime numbers.
2
3
5
7
11
13
17
19
23
29
Note, that you can build the same pipeline using buildIterator coroutine builder from the
standard library. Replace produce with buildIterator , send with yield , receive with
next , ReceiveChannel with Iterator , and get rid of the coroutine scope. You will not need
runBlocking either. However, the bene t of a pipeline that uses channels as shown above is that
it can actually use multiple CPU cores if you run it in Dispatchers.Default context.
Fan-out
Multiple coroutines may receive from the same channel, distributing work between themselves. Let
us start with a producer coroutine that is periodically producing integers (ten numbers per
second):
332
fun CoroutineScope.produceNumbers() = produce<Int> {
var x = 1 // start from 1
while (true) {
send(x++) // produce next
delay(100) // wait 0.1s
}
}
Then we can have several processor coroutines. In this example, they just print their id and
received number:
Now let us launch ve processors and let them work for almost a second. See what happens:
The output will be similar to the the following one, albeit the processor ids that receive each
speci c integer may be di erent:
Processor #2 received 1
Processor #4 received 2
Processor #0 received 3
Processor #1 received 4
Processor #3 received 5
Processor #2 received 6
Processor #4 received 7
Processor #0 received 8
Processor #1 received 9
Processor #3 received 10
Note, that cancelling a producer coroutine closes its channel, thus eventually terminating iteration
over the channel that processor coroutines are doing.
Also, pay attention to how we explicitly iterate over channel with for loop to perform fan-out in
launchProcessor code. Unlike consumeEach , this for loop pattern is perfectly safe to use
from multiple coroutines. If one of the processor coroutines fails, then others would still be
processing the channel, while a processor that is written via consumeEach always consumes
(cancels) the underlying channel on its normal or abnormal completion.
Fan-in
333
Multiple coroutines may send to the same channel. For example, let us have a channel of strings,
and a suspending function that repeatedly sends a speci ed string to this channel with a speci ed
delay:
Now, let us see what happens if we launch a couple of coroutines sending strings (in this example
we launch them in the context of the main thread as main coroutine's children):
foo
foo
BAR!
foo
foo
BAR!
Bu ered channels
The channels shown so far had no bu er. Unbu ered channels transfer elements when sender
and receiver meet each other (aka rendezvous). If send is invoked rst, then it is suspended until
receive is invoked, if receive is invoked rst, it is suspended until send is invoked.
Both Channel() factory function and produce builder take an optional capacity parameter to
specify bu er size. Bu er allows senders to send multiple elements before suspending, similar to
the BlockingQueue with a speci ed capacity, which blocks when bu er is full.
334
val channel = Channel<Int>(4) // create buffered channel
val sender = launch { // launch sender coroutine
repeat(10) {
println("Sending $it") // print before sending each element
channel.send(it) // will suspend when buffer is full
}
}
// don't receive anything... just wait....
delay(1000)
sender.cancel() // cancel sender coroutine
Sending 0
Sending 1
Sending 2
Sending 3
Sending 4
The rst four elements are added to the bu er and the sender suspends when trying to send the
fth one.
Send and receive operations to channels are fair with respect to the order of their invocation from
multiple coroutines. They are served in rst-in rst-out order, e.g. the rst coroutine to invoke
receive gets the element. In the following example two coroutines "ping" and "pong" are
receiving the "ball" object from the shared "table" channel.
335
The "ping" coroutine is started rst, so it is the rst one to receive the ball. Even though "ping"
coroutine immediately starts receiving the ball again after sending it back to the table, the ball gets
received by the "pong" coroutine, because it was already waiting for it:
ping Ball(hits=1)
pong Ball(hits=2)
ping Ball(hits=3)
pong Ball(hits=4)
Note, that sometimes channels may produce executions that look unfair due to the nature of the
executor that is being used. See this issue for details.
Ticker channels
Ticker channel is a special rendezvous channel that produces Unit every time given delay passes
since last consumption from this channel. Though it may seem to be useless standalone, it is a
useful building block to create complex time-based produce pipelines and operators that do
windowing and other time-dependent processing. Ticker channel can be used in select to perform
"on tick" action.
To create such channel use a factory method ticker. To indicate that no further elements are
needed use ReceiveChannel.cancel method on it.
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
336
}
Note that ticker is aware of possible consumer pauses and, by default, adjusts next produced
element delay if a pause occurs, trying to maintain a xed rate of produced elements.
337
Table of contents
Sequential by default
Assume that we have two suspending functions de ned elsewhere that do something useful like
some kind of remote service call or computation. We just pretend they are useful, but actually each
one just delays for a second for the purpose of this example:
We use a normal sequential invocation, because the code in the coroutine, just like in the regular
code, is sequential by default. The following example demonstrates it by measuring the total time it
takes to execute both suspending functions:
338
The answer is 42
Completed in 2017 ms
Conceptually, async is just like launch. It starts a separate coroutine which is a light-weight thread
that works concurrently with all the other coroutines. The di erence is that launch returns a Job
and does not carry any resulting value, while async returns a Deferred – a light-weight non-
blocking future that represents a promise to provide a result later. You can use .await() on a
deferred value to get its eventual result, but Deferred is also a Job , so you can cancel it if
needed.
The answer is 42
Completed in 1017 ms
This is twice as fast, because we have concurrent execution of two coroutines. Note, that
concurrency with coroutines is always explicit.
There is a laziness option to async using an optional start parameter with a value of
CoroutineStart.LAZY. It starts coroutine only when its result is needed by some await or if a start
function is invoked. Run the following example:
339
You can get full code here
The answer is 42
Completed in 1017 ms
So, here the two coroutines are de ned but not executed as in the previous example, but the
control is given to the programmer on when exactly to start the execution by calling start. We rst
start one , then start two , and then await for the individual coroutines to nish.
Note, that if we have called await in println and omitted start on individual coroutines, then we
would have got the sequential behaviour as await starts the coroutine execution and waits for the
execution to nish, which is not the intended use-case for laziness. The use-case for async(start
= CoroutineStart.LAZY) is a replacement for the standard lazy function in cases when
computation of the value involves suspending functions.
Async-style functions
Note, that these xxxAsync functions are not suspending functions. They can be used from
anywhere. However, their use always implies asynchronous (here meaning concurrent) execution of
their action with the invoking code.
340
// note, that we don't have `runBlocking` to the right of `main` in this example
fun main() {
val time = measureTimeMillis {
// we can initiate async actions outside of a coroutine
val one = somethingUsefulOneAsync()
val two = somethingUsefulTwoAsync()
// but waiting for a result must involve either suspending or blocking.
// here we use `runBlocking { ... }` to block the main thread while waiting for the
result
runBlocking {
println("The answer is ${one.await() + two.await()}")
}
}
println("Completed in $time ms")
}
This programming style with async functions is provided here only for illustration, because it is
a popular style in other programming languages. Using this style with Kotlin coroutines is
strongly discouraged for the reasons that are explained below.
Let us take Concurrent using async example and extract a function that concurrently performs
doSomethingUsefulOne and doSomethingUsefulTwo and returns the sum of their results.
Because async coroutines builder is de ned as extension on CoroutineScope we need to have it in
the scope and that is what coroutineScope function provides:
This way, if something goes wrong inside the code of concurrentSum function and it throws an
exception, all the coroutines that were launched in its scope are cancelled.
341
val time = measureTimeMillis {
println("The answer is ${concurrentSum()}")
}
println("Completed in $time ms")
We still have concurrent execution of both operations as evident from the output of the above
main function:
The answer is 42
Completed in 1017 ms
import kotlinx.coroutines.*
Note, how both rst async and awaiting parent are cancelled on the one child failure:
342
Table of contents
The coroutine context is a set of various elements. The main elements are the Job of the coroutine,
which we've seen before, and its dispatcher, which is covered in this section.
Coroutine context includes a coroutine dispatcher (see CoroutineDispatcher) that determines what
thread or threads the corresponding coroutine uses for its execution. Coroutine dispatcher can
con ne coroutine execution to a speci c thread, dispatch it to a thread pool, or let it run
uncon ned.
All coroutine builders like launch and async accept an optional CoroutineContext parameter that
can be used to explicitly specify the dispatcher for new coroutine and other context elements.
343
You can get full code here
When launch { ... } is used without parameters, it inherits the context (and thus dispatcher)
from the CoroutineScope that it is being launched from. In this case, it inherits the context of the
main runBlocking coroutine which runs in the main thread.
Dispatchers.Uncon ned is a special dispatcher that also appears to run in the main thread, but it
is, in fact, a di erent mechanism that is explained later.
The default dispatcher, that is used when coroutines are launched in GlobalScope, is represented
by Dispatchers.Default and uses shared background pool of threads, so
launch(Dispatchers.Default) { ... } uses the same dispatcher as
GlobalScope.launch { ... } .
newSingleThreadContext creates a new thread for the coroutine to run. A dedicated thread is a
very expensive resource. In a real application it must be either released, when no longer needed,
using close function, or stored in a top-level variable and reused throughout the application.
The Dispatchers.Uncon ned coroutine dispatcher starts coroutine in the caller thread, but only
until the rst suspension point. After suspension it resumes in the thread that is fully determined
by the suspending function that was invoked. Uncon ned dispatcher is appropriate when coroutine
does not consume CPU time nor updates any shared data (like UI) that is con ned to a speci c
thread.
On the other side, by default, a dispatcher for the outer CoroutineScope is inherited. The default
dispatcher for runBlocking coroutine, in particular, is con ned to the invoker thread, so inheriting it
has the e ect of con ning execution to this thread with a predictable FIFO scheduling.
344
Produces the output:
So, the coroutine that had inherited context of runBlocking {...} continues to execute in the
main thread, while the uncon ned one had resumed in the default executor thread that delay
function is using.
Uncon ned dispatcher is an advanced mechanism that can be helpful in certain corner cases
where dispatching of coroutine for its execution later is not needed or produces undesirable
side-e ects, because some operation in a coroutine must be performed right away.
Uncon ned dispatcher should not be used in general code.
Coroutines can suspend on one thread and resume on another thread. Even with a single-threaded
dispatcher it might be hard to gure out what coroutine was doing, where, and when. The common
approach to debugging applications with threads is to print the thread name in the log le on each
log statement. This feature is universally supported by logging frameworks. When using coroutines,
the thread name alone does not give much of a context, so kotlinx.coroutines includes
debugging facilities to make it easier.
val a = async {
log("I'm computing a piece of the answer")
6
}
val b = async {
log("I'm computing another piece of the answer")
7
}
log("The answer is ${a.await() * b.await()}")
There are three coroutines. The main coroutine (#1) – runBlocking one, and two coroutines
computing deferred values a (#2) and b (#3). They are all executing in the context of
runBlocking and are con ned to the main thread. The output of this code is:
345
The log function prints the name of the thread in square brackets and you can see, that it is the
main thread, but the identi er of the currently executing coroutine is appended to it. This
identi er is consecutively assigned to all created coroutines when debugging mode is turned on.
You can read more about debugging facilities in the documentation for newCoroutineContext
function.
Run the following code with -Dkotlinx.coroutines.debug JVM option (see debug):
It demonstrates several new techniques. One is using runBlocking with an explicitly speci ed
context, and the other one is using withContext function to change a context of a coroutine while
still staying in the same coroutine as you can see in the output below:
Note, that this example also uses use function from the Kotlin standard library to release threads
that are created with newSingleThreadContext when they are no longer needed.
The coroutine's Job is part of its context. The coroutine can retrieve it from its own context using
coroutineContext[Job] expression:
346
Note, that isActive in CoroutineScope is just a convenient shortcut for
coroutineContext[Job]?.isActive == true .
Children of a coroutine
When a coroutine is launched in the CoroutineScope of another coroutine, it inherits its context via
CoroutineScope.coroutineContext and the Job of the new coroutine becomes a child of the parent
coroutine's job. When the parent coroutine is cancelled, all its children are recursively cancelled,
too.
However, when GlobalScope is used to launch a coroutine, it is not tied to the scope it was
launched from and operates independently.
Parental responsibilities
A parent coroutine always waits for completion of all its children. Parent does not have to explicitly
track all the children it launches and it does not have to use Job.join to wait for them at the end:
347
// launch a coroutine to process some kind of incoming request
val request = launch {
repeat(3) { i -> // launch a few children jobs
launch {
delay((i + 1) * 200L) // variable delay 200ms, 400ms, 600ms
println("Coroutine $i is done")
}
}
println("request: I'm done and I don't explicitly join my children that are still
active")
}
request.join() // wait for completion of the request, including all its children
println("Now processing of the request is complete")
request: I'm done and I don't explicitly join my children that are still active
Coroutine 0 is done
Coroutine 1 is done
Coroutine 2 is done
Now processing of the request is complete
Automatically assigned ids are good when coroutines log often and you just need to correlate log
records coming from the same coroutine. However, when coroutine is tied to the processing of a
speci c request or doing some speci c background task, it is better to name it explicitly for
debugging purposes. CoroutineName context element serves the same function as a thread name.
It'll get displayed in the thread name that is executing this coroutine when debugging mode is
turned on.
348
[main @main#1] Started main coroutine
[main @v1coroutine#2] Computing v1
[main @v2coroutine#3] Computing v2
[main @main#1] The answer for v1 / v2 = 42
Sometimes we need to de ne multiple elements for coroutine context. We can use + operator for
that. For example, we can launch a coroutine with an explicitly speci ed dispatcher and an explicitly
speci ed name at the same time:
launch(Dispatchers.Default + CoroutineName("test")) {
println("I'm working in thread ${Thread.currentThread().name}")
}
Let us put our knowledge about contexts, children and jobs together. Assume that our application
has an object with a lifecycle, but that object is not a coroutine. For example, we are writing an
Android application and launch various coroutines in the context of an Android activity to perform
asynchronous operations to fetch and update data, do animations, etc. All of these coroutines must
be cancelled when activity is destroyed to avoid memory leaks.
We manage a lifecycle of our coroutines by creating an instance of Job that is tied to the lifecycle of
our activity. A job instance is created using Job() factory function when activity is created and it is
cancelled when an activity is destroyed like this:
fun create() {
job = Job()
}
fun destroy() {
job.cancel()
}
// to be continued ...
We also implement CoroutineScope interface in this Actvity class. We only need to provide an
override for its CoroutineScope.coroutineContext property to specify the context for coroutines
launched in its scope. We combine the desired dispatcher (we used Dispatchers.Default in this
example) and a job:
349
// class Activity continues
override val coroutineContext: CoroutineContext
get() = Dispatchers.Default + job
// to be continued ...
Now, we can launch coroutines in the scope of this Activity without having to explicitly specify
their context. For the demo, we launch ten coroutines that delay for a di erent time:
In our main function we create activity, call our test doSomething function, and destroy activity
after 500ms. This cancels all the coroutines that were launched which we can con rm by noting
that it does not print onto the screen anymore if we wait:
Launched coroutines
Coroutine 0 is done
Coroutine 1 is done
Destroying activity!
As you can see, only the rst two coroutines had printed a message and the others were cancelled
by a single invocation of job.cancel() in Activity.destroy() .
Thread-local data
Sometimes it is convenient to have an ability to pass some thread-local data, but, for coroutines,
which are not bound to any particular thread, it is hard to achieve it manually without writing a lot
of boilerplate.
350
For ThreadLocal, asContextElement extension function is here for the rescue. It creates an
additional context element, which keeps the value of the given ThreadLocal and restores it
every time the coroutine switches its context.
threadLocal.set("main")
println("Pre-main, current thread: ${Thread.currentThread()}, thread local value:
'${threadLocal.get()}'")
val job = launch(Dispatchers.Default + threadLocal.asContextElement(value = "launch")) {
println("Launch start, current thread: ${Thread.currentThread()}, thread local value:
'${threadLocal.get()}'")
yield()
println("After yield, current thread: ${Thread.currentThread()}, thread local value:
'${threadLocal.get()}'")
}
job.join()
println("Post-main, current thread: ${Thread.currentThread()}, thread local value:
'${threadLocal.get()}'")
In this example we launch new coroutine in a background thread pool using Dispatchers.Default,
so it works on a di erent threads from a thread pool, but it still has the value of thread local
variable, that we've speci ed using threadLocal.asContextElement(value = "launch") ,
no matter on what thread the coroutine is executed. Thus, output (with debug) is:
ThreadLocal has rst-class support and can be used with any primitive kotlinx.coroutines
provides. It has one key limitation: when thread-local is mutated, a new value is not propagated to
the coroutine caller (as context element cannot track all ThreadLocal object accesses) and
updated value is lost on the next suspension. Use withContext to update the value of the thread-
local in a coroutine, see asContextElement for more details.
Alternatively, a value can be stored in a mutable box like class Counter(var i: Int) , which
is, in turn, stored in a thread-local variable. However, in this case you are fully responsible to
synchronize potentially concurrent modi cations to the variable in this mutable box.
For advanced usage, for example for integration with logging MDC, transactional contexts or any
other libraries which internally use thread-locals for passing data, see documentation for
ThreadContextElement interface that should be implemented.
351
Table of contents
— Exception handling
— Exception propagation
— CoroutineExceptionHandler
— Cancellation and exceptions
— Exceptions aggregation
— Supervision
— Supervision job
— Supervision scope
— Exceptions in supervised coroutines
Exception handling
This section covers exception handling and cancellation on exceptions. We already know that
cancelled coroutine throws CancellationException in suspension points and that it is ignored by
coroutines machinery. But what happens if an exception is thrown during cancellation or multiple
children of the same coroutine throw an exception?
Exception propagation
Coroutine builders come in two avors: propagating exceptions automatically (launch and actor) or
exposing them to users (async and produce). The former treat exceptions as unhandled, similar to
Java's Thread.uncaughtExceptionHandler , while the latter are relying on the user to
consume the nal exception, for example via await or receive (produce and receive are covered
later in Channels section).
352
import kotlinx.coroutines.*
CoroutineExceptionHandler
But what if one does not want to print all exceptions to the console? CoroutineExceptionHandler
context element is used as generic catch block of coroutine where custom logging or exception
handling may take place. It is similar to using Thread.uncaughtExceptionHandler.
On JVM it is possible to rede ne global exception handler for all coroutines by registering
CoroutineExceptionHandler via ServiceLoader. Global exception handler is similar to
Thread.defaultUncaughtExceptionHandler which is used when no more speci c handlers
are registered. On Android, uncaughtExceptionPreHandler is installed as a global coroutine
exception handler.
353
val handler = CoroutineExceptionHandler { _, exception ->
println("Caught $exception")
}
val job = GlobalScope.launch(handler) {
throw AssertionError()
}
val deferred = GlobalScope.async(handler) {
throw ArithmeticException() // Nothing will be printed, relying on user to call
deferred.await()
}
joinAll(job, deferred)
Caught java.lang.AssertionError
Cancelling child
Child is cancelled
Parent is not cancelled
354
If a coroutine encounters exception other than CancellationException , it cancels its parent
with that exception. This behaviour cannot be overridden and is used to provide stable coroutines
hierarchies for structured concurrency which do not depend on CoroutineExceptionHandler
implementation. The original exception is handled by the parent when all its children terminate.
Exceptions aggregation
What happens if multiple children of a coroutine throw an exception? The general rule is "the rst
exception wins", so the rst thrown exception is exposed to the handler. But that may cause lost
exceptions, for example if coroutine throws an exception in its finally block. So, additional
exceptions are suppressed.
355
One of the solutions would have been to report each exception separately, but then
Deferred.await should have had the same mechanism to avoid behavioural inconsistency and
this would cause implementation details of a coroutines (whether it had delegated parts of its
work to its children or not) to leak to its exception handler.
import kotlinx.coroutines.*
import java.io.*
Note: This above code will work properly only on JDK7+ that supports suppressed exceptions
Note, this mechanism currently works only on Java version 1.7+. Limitation on JS and Native is
temporary and will be xed in the future.
356
val handler = CoroutineExceptionHandler { _, exception ->
println("Caught original $exception")
}
val job = GlobalScope.launch(handler) {
val inner = launch {
launch {
launch {
throw IOException()
}
}
}
try {
inner.join()
} catch (e: CancellationException) {
println("Rethrowing CancellationException with original cause")
throw e
}
}
job.join()
Supervision
As we have studied before, cancellation is a bidirectional relationship propagating through the
whole coroutines hierarchy. But what if unidirectional cancellation is required?
Good example of such requirement can be a UI component with the job de ned in its scope. If any
of UI's child task has failed, it is not always necessary to cancel (e ectively kill) the whole UI
component, but if UI component is destroyed (and its job is cancelled), then it is necessary to fail all
children jobs as their result is no longer required.
Another example is a server process that spawns several children jobs and needs to supervise their
execution, tracking their failures and restarting just those children jobs that had failed.
Supervision job
For these purposes SupervisorJob can be used. It is similar to a regular Job with the only exception
that cancellation is propagated only downwards. It is easy to demonstrate with an example:
import kotlinx.coroutines.*
357
throw AssertionError("First child is cancelled")
}
// launch the second child
val secondChild = launch {
firstChild.join()
// Cancellation of the first child is not propagated to the second child
println("First child is cancelled: ${firstChild.isCancelled}, but second one is
still active")
try {
delay(Long.MAX_VALUE)
} finally {
// But cancellation of the supervisor is propagated
println("Second child is cancelled because supervisor is cancelled")
}
}
// wait until the first child fails & completes
firstChild.join()
println("Cancelling supervisor")
supervisor.cancel()
secondChild.join()
}
}
Supervision scope
For scoped concurrency supervisorScope can be used instead of coroutineScope for the same
purpose. It propagates cancellation only in one direction and cancels all children only if it has failed
itself. It also waits for all children before completion just like coroutineScope does.
358
import kotlin.coroutines.*
import kotlinx.coroutines.*
Child is sleeping
Throwing exception from scope
Child is cancelled
Caught assertion error
Another crucial di erence between regular and supervisor jobs is exception handling. Every child
should handle its exceptions by itself via exception handling mechanisms. This di erence comes
from the fact that child's failure is not propagated to the parent.
import kotlin.coroutines.*
import kotlinx.coroutines.*
359
You can get full code here
Scope is completing
Child throws an exception
Caught java.lang.AssertionError
Scope is completed
360
Table of contents
Let us have two producers of strings: fizz and buzz . The fizz produces "Fizz" string every 300
ms:
Using receive suspending function we can receive either from one channel or the other. But select
expression allows us to receive from both simultaneously using its onReceive clauses:
361
suspend fun selectFizzBuzz(fizz: ReceiveChannel<String>, buzz: ReceiveChannel<String>) {
select<Unit> { // <Unit> means that this select expression does not produce any result
fizz.onReceive { value -> // this is the first select clause
println("fizz -> '$value'")
}
buzz.onReceive { value -> // this is the second select clause
println("buzz -> '$value'")
}
}
}
Selecting on close
The onReceive clause in select fails when the channel is closed causing the corresponding
select to throw an exception. We can use onReceiveOrNull clause to perform a speci c action
when the channel is closed. The following example also shows that select is an expression that
returns the result of its selected clause:
362
Let's use it with channel a that produces "Hello" string four times and channel b that produces
"World" four times:
val a = produce<String> {
repeat(4) { send("Hello $it") }
}
val b = produce<String> {
repeat(4) { send("World $it") }
}
repeat(8) { // print first eight results
println(selectAorB(a, b))
}
coroutineContext.cancelChildren()
The result of this code is quite interesting, so we'll analyze it in mode detail:
First of all, select is biased to the rst clause. When several clauses are selectable at the same
time, the rst one among them gets selected. Here, both channels are constantly producing strings,
so a channel, being the rst clause in select, wins. However, because we are using unbu ered
channel, the a gets suspended from time to time on its send invocation and gives a chance for b
to send, too.
The second observation, is that onReceiveOrNull gets immediately selected when the channel is
already closed.
Selecting to send
Select expression has onSend clause that can be used for a great good in combination with a
biased nature of selection.
Let us write an example of producer of integers that sends its values to a side channel when the
consumers on its primary channel cannot keep up with it:
363
fun CoroutineScope.produceNumbers(side: SendChannel<Int>) = produce<Int> {
for (num in 1..10) { // produce 10 numbers from 1 to 10
delay(100) // every 100 ms
select<Unit> {
onSend(num) {} // Send to the primary channel
side.onSend(num) {} // or to the side channel
}
}
}
Consuming 1
Side channel has 2
Side channel has 3
Consuming 4
Side channel has 5
Side channel has 6
Consuming 7
Side channel has 8
Side channel has 9
Consuming 10
Done consuming
Deferred values can be selected using onAwait clause. Let us start with an async function that
returns a deferred string value after a random delay:
364
Now the main function awaits for the rst of them to complete and counts the number of deferred
values that are still active. Note, that we've used here the fact that select expression is a Kotlin
DSL, so we can provide clauses for it using an arbitrary code. In this case we iterate over a list of
deferred values to provide onAwait clause for each deferred value.
Let us write a channel producer function that consumes a channel of deferred string values, waits
for each received deferred value, but only until the next deferred value comes over or the channel
is closed. This example puts together onReceiveOrNull and onAwait clauses in the same select :
To test it, we'll use a simple async function that resolves to a speci ed string after a speci ed time:
365
fun CoroutineScope.asyncString(str: String, time: Long) = async {
delay(time)
str
}
The main function just launches a coroutine to print results of switchMapDeferreds and sends
some test data to it:
BEGIN
Replace
END
Channel was closed
366
Table of contents
The problem
Let us launch a hundred coroutines all doing the same action thousand times. We'll also measure
their completion time for further comparisons:
We start with a very simple action that increments a shared mutable variable using multi-threaded
Dispatchers.Default that is used in GlobalScope.
GlobalScope.massiveRun {
counter++
}
println("Counter = $counter")
367
What does it print at the end? It is highly unlikely to ever print "Counter = 100000", because a
thousand coroutines increment the counter concurrently from multiple threads without any
synchronization.
Note: if you have an old system with 2 or fewer CPUs, then you will consistently see 100000,
because the thread pool is running in only one thread in this case. To reproduce the problem
you'll need to make the following change:
There is common misconception that making a variable volatile solves concurrency problem.
Let us try it:
import kotlinx.coroutines.*
import kotlin.system.*
368
}
println("Counter = $counter")
}
This code works slower, but we still don't get "Counter = 100000" at the end, because volatile
variables guarantee linearizable (this is a technical term for "atomic") reads and writes to the
corresponding variable, but do not provide atomicity of larger actions (increment in our case).
The general solution that works both for threads and for coroutines is to use a thread-safe (aka
synchronized, linearizable, or atomic) data structure that provides all the necessarily
synchronization for the corresponding operations that needs to be performed on a shared state. In
the case of a simple counter we can use AtomicInteger class which has atomic
incrementAndGet operations:
GlobalScope.massiveRun {
counter.incrementAndGet()
}
println("Counter = ${counter.get()}")
This is the fastest solution for this particular problem. It works for plain counters, collections,
queues and other standard data structures and basic operations on them. However, it does not
easily scale to complex state or to complex operations that do not have ready-to-use thread-safe
implementations.
Thread con nement is an approach to the problem of shared mutable state where all access to the
particular shared state is con ned to a single thread. It is typically used in UI applications, where all
UI state is con ned to the single event-dispatch/application thread. It is easy to apply with
coroutines by using a
single-threaded context.
369
This code works very slowly, because it does ne-grained thread-con nement. Each individual
increment switches from multi-threaded Dispatchers.Default context to the single-threaded
context using withContext block.
In practice, thread con nement is performed in large chunks, e.g. big pieces of state-updating
business logic are con ned to the single thread. The following example does it like that, running
each coroutine in the single-threaded context to start with. Here we use CoroutineScope() function
to convert coroutine context reference to CoroutineScope:
Mutual exclusion
Mutual exclusion solution to the problem is to protect all modi cations of the shared state with a
critical section that is never executed concurrently. In a blocking world you'd typically use
synchronized or ReentrantLock for that. Coroutine's alternative is called Mutex. It has lock
and unlock functions to delimit a critical section. The key di erence is that Mutex.lock() is a
suspending function. It does not block a thread.
There is also withLock extension function that conveniently represents mutex.lock(); try {
... } finally { mutex.unlock() } pattern:
GlobalScope.massiveRun {
mutex.withLock {
counter++
}
}
println("Counter = $counter")
The locking in this example is ne-grained, so it pays the price. However, it is a good choice for
some situations where you absolutely must modify some shared state periodically, but there is no
natural thread that this state is con ned to.
Actors
370
An actor is an entity made up of a combination of a coroutine, the state that is con ned and
encapsulated into this coroutine, and a channel to communicate with other coroutines. A simple
actor can be written as a function, but an actor with a complex state is better suited for a class.
There is an actor coroutine builder that conveniently combines actor's mailbox channel into its
scope to receive messages from and combines the send channel into the resulting job object, so
that a single reference to the actor can be carried around as its handle.
The rst step of using an actor is to de ne a class of messages that an actor is going to process.
Kotlin's sealed classes are well suited for that purpose. We de ne CounterMsg sealed class with
IncCounter message to increment a counter and GetCounter message to get its value. The
later needs to send a response. A CompletableDeferred communication primitive, that represents
a single value that will be known (communicated) in the future, is used here for that purpose.
It does not matter (for correctness) what context the actor itself is executed in. An actor is a
coroutine and a coroutine is executed sequentially, so con nement of the state to the speci c
coroutine works as a solution to the problem of shared mutable state. Indeed, actors may modify
their own private state, but can only a ect each other through messages (avoiding the need for any
locks).
371
Actor is more e cient than locking under load, because in this case it always has work to do and it
does not have to switch to a di erent context at all.
Note, that an actor coroutine builder is a dual of produce coroutine builder. An actor is
associated with the channel that it receives messages from, while a producer is associated with
the channel that it sends elements to.
372
Tools
Documenting Kotlin Code
The language used to document Kotlin code (the equivalent of Java's JavaDoc) is called KDoc. In its
essence, KDoc combines JavaDoc's syntax for block tags (extended to support Kotlin's speci c
constructs) and Markdown for inline markup.
Dokka has plugins for Gradle, Maven and Ant, so you can integrate documentation generation into
your build process.
KDoc Syntax
Just like with JavaDoc, KDoc comments start with /** and end with */ . Every line of the comment
may begin with an asterisk, which is not considered part of the contents of the comment.
By convention, the rst paragraph of the documentation text (the block of text until the rst blank
line) is the summary description of the element, and the following text is the detailed description.
Every block tag begins on a new line and starts with the @ character.
/**
* A group of *members*.
*
* This class has no useful logic; it's just a documentation example.
*
* @param T the type of a member in this group.
* @property name the name of this group.
* @constructor Creates an empty group.
*/
class Group<T>(val name: String) {
/**
* Adds a [member] to this group.
* @return the new size of the group.
*/
fun add(member: T): Int { ... }
}
Block Tags
373
KDoc currently supports the following block tags:
@param <name>
@return
@constructor
@receiver
@property <name>
Documents the property of a class which has the speci ed name. This tag can be used for
documenting properties declared in the primary constructor, where putting a doc comment
directly before the property de nition would be awkward.
Documents an exception which can be thrown by a method. Since Kotlin does not have checked
exceptions, there is also no expectation that all possible exceptions are documented, but you can
still use this tag when it provides useful information for users of the class.
@sample <identifier>
Embeds the body of the function with the speci ed quali ed name into the documentation for the
current element, in order to show an example of how the element could be used.
@see <identifier>
Adds a link to the speci ed class or method to the See Also block of the documentation.
@author
@since
Speci es the version of the software in which the element being documented was introduced.
374
@suppress
Excludes the element from the generated documentation. Can be used for elements which are not
part of the o cial API of a module but still have to be visible externally.
KDoc does not support the @deprecated tag. Instead, please use the @Deprecated
annotation.
Inline Markup
For inline markup, KDoc uses the regular Markdown syntax, extended to support a shorthand
syntax for linking to other elements in the code.
Linking to Elements
To link to another element (class, method, property or parameter), simply put its name in square
brackets:
Use the method [foo] for this purpose.
If you want to specify a custom label for the link, use the Markdown reference-style syntax:
Use [this method][foo] for this purpose.
You can also use quali ed names in the links. Note that, unlike JavaDoc, quali ed names always use
the dot character to separate the components, even before a method name:
Use [kotlin.reflect.KClass.properties] to enumerate the properties of the class.
Names in links are resolved using the same rules as if the name was used inside the element being
documented. In particular, this means that if you have imported a name into the current le, you
don't need to fully qualify it when you use it in a KDoc comment.
Note that KDoc does not have any syntax for resolving overloaded members in links. Since the
Kotlin documentation generation tool puts the documentation for all overloads of a function on
the same page, identifying a speci c overloaded function is not required for the link to work.
Inside the le, the documentation for the module as a whole and for individual packages is
introduced by the corresponding rst-level headings. The text of the heading must be "Module
<module name> " for the module, and "Package <package qualified name> " for a package.
375
# Module kotlin-demo
# Package org.jetbrains.kotlin.demo
## Level 2 heading
# Package org.jetbrains.kotlin.demo2
376
Annotation Processing with Kotlin
Annotation processors (see JSR 269) are supported in Kotlin with the kapt compiler plugin.
Being short, you can use libraries such as Dagger or Data Binding in your Kotlin projects.
Please read below about how to apply the kapt plugin to your Gradle/Maven build.
Using in Gradle
Apply the kotlin-kapt Gradle plugin:
plugins {
id "org.jetbrains.kotlin.kapt" version "1.3.11"
}
Then add the respective dependencies using the kapt con guration in your dependencies
block:
dependencies {
kapt 'groupId:artifactId:version'
}
If you previously used the Android support for annotation processors, replace usages of the
annotationProcessor con guration with kapt . If your project contains Java classes, kapt will
also take care of them.
If you use annotation processors for your androidTest or test sources, the respective kapt
con gurations are named kaptAndroidTest and kaptTest . Note that kaptAndroidTest
and kaptTest extends kapt , so you can just provide the kapt dependency and it will be
available both for production sources and tests.
kapt {
arguments {
arg("key", "value")
}
}
377
kapt {
javacOptions {
// Increase the max count of errors from annotation processors.
// Default is 100.
option("-Xmaxerrs", 500)
}
}
kapt {
correctErrorTypes = true
}
Using in Maven
Add an execution of the kapt goal from kotlin-maven-plugin before compile :
<execution>
<id>kapt</id>
<goals>
<goal>kapt</goal>
</goals>
<configuration>
<sourceDirs>
<sourceDir>src/main/kotlin</sourceDir>
<sourceDir>src/main/java</sourceDir>
</sourceDirs>
<annotationProcessorPaths>
<!-- Specify your annotation processors here. -->
<annotationProcessorPath>
<groupId>com.google.dagger</groupId>
<artifactId>dagger-compiler</artifactId>
<version>2.9</version>
</annotationProcessorPath>
</annotationProcessorPaths>
</configuration>
</execution>
You can nd a complete sample project showing the use of Kotlin, Maven and Dagger in the Kotlin
examples repository.
Please note that kapt is still not supported for IntelliJ IDEA’s own build system. Launch the build
from the “Maven Projects” toolbar whenever you want to re-run the annotation processing.
Using in CLI
Kapt compiler plugin is available in the binary distribution of the Kotlin compiler.
You can attach the plugin by providing the path to its JAR le using the Xplugin kotlinc option:
378
-Xplugin=$KOTLIN_HOME/lib/kotlin-annotation-processing.jar
— classes (required): An output path for the generated class les and resources.
— stubs (required): An output path for the stub les. In other words, some temporary directory.
— aptMode (required)
An example:
-P plugin:org.jetbrains.kotlin.kapt3:sources=build/kapt/sources
-P plugin:org.jetbrains.kotlin.kapt3:classes=build/kapt/classes
-P plugin:org.jetbrains.kotlin.kapt3:stubs=build/kapt/stubs
-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=lib/ap.jar
-P plugin:org.jetbrains.kotlin.kapt3:apclasspath=lib/anotherAp.jar
-P plugin:org.jetbrains.kotlin.kapt3:correctErrorTypes=true
379
Note that Kapt does not support multiple rounds for the generated Kotlin les.
oos.writeInt(options.size)
for ((key, value) in options.entries) {
oos.writeUTF(key)
oos.writeUTF(value)
}
oos.flush()
return Base64.getEncoder().encodeToString(os.toByteArray())
}
380
Using Gradle
In order to build Kotlin with Gradle you should set up the kotlin-gradle plugin, apply it to your
project and add kotlin-stdlib dependencies. Those actions may also be performed automatically in
IntelliJ IDEA by invoking the Tools | Kotlin | Con gure Kotlin in Project action.
buildscript {
ext.kotlin_version = '1.3.11'
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
This is not required when using Kotlin Gradle plugin 1.1.1 and above with the Gradle plugins DSL,
and with Gradle Kotlin DSL.
Or, starting with Kotlin 1.1.1, the plugin can be applied using the Gradle plugins DSL:
plugins {
id "org.jetbrains.kotlin.jvm" version "1.3.11"
}
The version should be literal in this block, and it cannot be applied from another build script.
plugins {
kotlin("jvm") version "1.3.11"
}
Kotlin sources can be mixed with Java sources in the same folder, or in di erent folders. The
default convention is using di erent folders:
381
project
- src
- main (root)
- kotlin
- java
The corresponding sourceSets property should be updated if not using the default convention:
sourceSets {
main.kotlin.srcDirs += 'src/main/myKotlin'
main.java.srcDirs += 'src/main/myJava'
}
With Gradle Kotlin DSL, con gure source sets with java.sourceSets { ... } instead.
Targeting JavaScript
When targeting JavaScript, a di erent plugin should be applied:
This plugin only works for Kotlin les so it is recommended to keep Kotlin and Java les separate (if
it's the case that the same project contains Java les). As with targeting the JVM, if not using the
default convention, we need to specify the source folder using sourceSets:
sourceSets {
main.kotlin.srcDirs += 'src/main/myKotlin'
}
In addition to the output JavaScript le, the plugin by default creates an additional JS le with binary
descriptors. This le is required if you're building a re-usable library that other Kotlin modules can
depend on, and should be distributed together with the result of translation. The generation is
controlled by the kotlinOptions.metaInfo option:
compileKotlin2Js {
kotlinOptions.metaInfo = true
}
Targeting Android
Android's Gradle model is a little di erent from ordinary Gradle, so if we want to build an Android
project written in Kotlin, we need kotlin-android plugin instead of kotlin:
buildscript {
ext.kotlin_version = '1.3.11'
...
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
382
Don't forget to con gure the standard library dependency.
Android Studio
android {
...
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
}
This lets Android Studio know that the kotlin directory is a source root, so when the project model
is loaded into the IDE it will be properly recognized. Alternatively, you can put Kotlin classes in the
Java source directory, typically located in src/main/java .
repositories {
mavenCentral()
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib"
}
If you're targeting JDK 7 or JDK 8, you can use extended versions of the Kotlin standard library
which contain additional extension functions for APIs added in new JDK versions. Instead of
kotlin-stdlib , use one of the following dependencies:
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk7"
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
With Gradle Kotlin DSL, the following notation for the dependencies is equivalent:
dependencies {
compile(kotlin("stdlib"))
// or one of:
compile(kotlin("stdlib-jdk7"))
compile(kotlin("stdlib-jdk8"))
}
If your project uses Kotlin re ection or testing facilities, you need to add the corresponding
dependencies as well:
383
compile "org.jetbrains.kotlin:kotlin-reflect"
testCompile "org.jetbrains.kotlin:kotlin-test"
testCompile "org.jetbrains.kotlin:kotlin-test-junit"
compile(kotlin("reflect"))
testCompile(kotlin("test"))
testCompile(kotlin("test-junit"))
Starting with Kotlin 1.1.2, the dependencies with group org.jetbrains.kotlin are by default
resolved with the version taken from the applied plugin. You can provide the version manually
using the full dependency notation like compile "org.jetbrains.kotlin:kotlin-
stdlib:$kotlin_version" , or kotlin("stdlib", kotlinVersion) in Gradle Kotlin DSL.
Annotation processing
See the description of Kotlin annotation processing tool ( kapt ).
Incremental compilation
Kotlin supports optional incremental compilation in Gradle. Incremental compilation tracks
changes of source les between builds so only les a ected by these changes would be compiled.
The kapt annotation processing tasks are not cached by default since annotation processors run
arbitrary code that may not necessarily transform the task inputs into the outputs, might access
and modify the les that are not tracked by Gradle etc. To enable caching for kapt anyway, add the
following lines to the build script:
kapt {
useBuildCache = true
}
384
To disable the caching for all Kotlin tasks, set the system property ag
kotlin.caching.enabled to false (run the build with the argument -
Dkotlin.caching.enabled=false ).
Compiler Options
To specify additional compilation options, use the kotlinOptions property of a Kotlin
compilation task.
When targeting the JVM, the tasks are called compileKotlin for production code and
compileTestKotlin for test code. The tasks for custom source sets are called accordingly to the
compile<Name>Kotlin pattern.
The names of the tasks in Android Projects contain the build variant names and follow the pattern
compile<BuildVariant>Kotlin , for example, compileDebugKotlin ,
compileReleaseUnitTestKotlin .
compileKotlin {
kotlinOptions.suppressWarnings = true
}
compileKotlin {
kotlinOptions {
suppressWarnings = true
}
}
With Gradle Kotlin DSL, get the task from the project's tasks rst:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
// ...
compileKotlin.kotlinOptions.suppressWarnings = true
Use the types Kotlin2JsCompile and KotlinCompileCommon for the JS and Common targets,
accordingly.
It is also possible to con gure all Kotlin compilation tasks in the project:
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile::class.java).all {
kotlinOptions { ... }
}
385
Attributes common for JVM, JS, and JS DCE
Name Description Possible values Default value
allWarningsAsErrors Report an error if there are any warnings false
suppressWarnings Generate no warnings false
verbose Enable verbose logging output false
freeCompilerArgs A list of additional compiler arguments []
Generating documentation
386
To generate documentation for Kotlin projects, use Dokka; please refer to the Dokka README for
con guration instructions. Dokka supports mixed-language projects and can generate output in
multiple formats, including standard JavaDoc.
OSGi
For OSGi support see the Kotlin OSGi page.
Examples
The following examples show di erent possibilities of con guring the Gradle plugin:
— Kotlin
— Mixed Java and Kotlin
— Android
— JavaScript
387
Using Maven
<properties>
<kotlin.version>1.3.11</kotlin.version>
</properties>
Dependencies
Kotlin has an extensive standard library that can be used in your applications. Con gure the
following dependency in the pom le:
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
If you're targeting JDK 7 or JDK 8, you can use extended versions of the Kotlin standard library
which contain additional extension functions for APIs added in new JDK versions. Instead of
kotlin-stdlib , use kotlin-stdlib-jdk7 or kotlin-stdlib-jdk8 , depending on your
JDK version (for Kotlin 1.1.x use kotlin-stdlib-jre7 and kotlin-stdlib-jre8 as the jdk
counterparts were introduced in 1.2.0).
If your project uses Kotlin re ection or testing facilities, you need to add the corresponding
dependencies as well. The artifact IDs are kotlin-reflect for the re ection library, and
kotlin-test and kotlin-test-junit for the testing libraries.
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
</build>
388
<build>
<plugins>
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<goals> <goal>compile</goal> </goals>
</execution>
<execution>
<id>test-compile</id>
<goals> <goal>test-compile</goal> </goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
389
<build>
<plugins>
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<goals> <goal>compile</goal> </goals>
<configuration>
<sourceDirs>
<sourceDir>${project.basedir}/src/main/kotlin</sourceDir>
<sourceDir>${project.basedir}/src/main/java</sourceDir>
</sourceDirs>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<goals> <goal>test-compile</goal> </goals>
<configuration>
<sourceDirs>
<sourceDir>${project.basedir}/src/test/kotlin</sourceDir>
<sourceDir>${project.basedir}/src/test/java</sourceDir>
</sourceDirs>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<executions>
<!-- Replacing default-compile as it is treated specially by maven -->
<execution>
<id>default-compile</id>
<phase>none</phase>
</execution>
<!-- Replacing default-testCompile as it is treated specially by maven -->
<execution>
<id>default-testCompile</id>
<phase>none</phase>
</execution>
<execution>
<id>java-compile</id>
<phase>compile</phase>
<goals> <goal>compile</goal> </goals>
</execution>
<execution>
<id>java-test-compile</id>
<phase>test-compile</phase>
<goals> <goal>testCompile</goal> </goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Incremental compilation
390
To make your builds faster, you can enable incremental compilation for Maven (supported since
Kotlin 1.1.2). In order to do that, de ne the kotlin.compiler.incremental property:
<properties>
<kotlin.compiler.incremental>true</kotlin.compiler.incremental>
</properties>
Annotation processing
See the description of Kotlin annotation processing tool ( kapt ).
Coroutines support
Coroutines support is an experimental feature in Kotlin 1.2, so the Kotlin compiler reports a
warning when you use coroutines in your project. To turn o the warning, add the following block
to your pom.xml le:
<configuration>
<experimentalCoroutines>enable</experimentalCoroutines>
</configuration>
Jar le
To create a small Jar le containing just the code from your module, include the following under
build->plugins in your Maven pom.xml le, where main.class is de ned as a property and
points to the main Kotlin or Java class:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>${main.class}</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
Self-contained Jar le
To create a self-contained Jar le containing the code from your module along with dependencies,
include the following under build->plugins in your Maven pom.xml le, where main.class
is de ned as a property and points to the main Kotlin or Java class:
391
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals> <goal>single</goal> </goals>
<configuration>
<archive>
<manifest>
<mainClass>${main.class}</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
This self-contained jar le can be passed directly to a JRE to run your application:
Targeting JavaScript
In order to compile JavaScript code, you need to use the js and test-js goals for the compile
execution:
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<executions>
<execution>
<id>compile</id>
<phase>compile</phase>
<goals>
<goal>js</goal>
</goals>
</execution>
<execution>
<id>test-compile</id>
<phase>test-compile</phase>
<goals>
<goal>test-js</goal>
</goals>
</execution>
</executions>
</plugin>
392
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-js</artifactId>
<version>${kotlin.version}</version>
For unit testing support, you also need to add a dependency on the kotlin-test-js artifact.
See the Getting Started with Kotlin and JavaScript with Maven tutorial for more information.
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<executions>...</executions>
<configuration>
<nowarn>true</nowarn> <!-- Disable warnings -->
<args>
<arg>-Xjsr305=strict</arg> <!-- Enable strict mode for JSR-305 annotations -->
...
</args>
</configuration>
</plugin>
<project ...>
<properties>
<kotlin.compiler.languageVersion>1.0</kotlin.compiler.languageVersion>
</properties>
</project>
393
Attributes speci c for JVM
Name Property name Description Possible Default
values value
jvmTarget kotlin.compiler.jvmTarget Target version of the generated JVM bytecode "1.6", "1.6"
"1.8"
jdkHome kotlin.compiler.jdkHome Path to JDK home directory to include into
classpath, if differs from default JAVA_HOME
Generating documentation
The standard JavaDoc generation plugin ( maven-javadoc-plugin ) does not support Kotlin code.
To generate documentation for Kotlin projects, use Dokka; please refer to the Dokka README for
con guration instructions. Dokka supports mixed-language projects and can generate output in
multiple formats, including standard JavaDoc.
OSGi
For OSGi support see the Kotlin OSGi page.
Examples
An example Maven project can be downloaded directly from the GitHub repository
394
Using Ant
These tasks are de ned in the kotlin-ant.jar library which is located in the lib folder for the Kotlin
Compiler Ant version 1.8.2+ is required.
<target name="build">
<kotlinc src="hello.kt" output="hello.jar"/>
</target>
</project>
where ${kotlin.lib} points to the folder where the Kotlin standalone compiler was unzipped.
<target name="build">
<kotlinc output="hello.jar">
<src path="root1"/>
<src path="root2"/>
</kotlinc>
</target>
</project>
395
<project name="Ant Task Test" default="build">
<typedef resource="org/jetbrains/kotlin/ant/antlib.xml"
classpath="${kotlin.lib}/kotlin-ant.jar"/>
<target name="build">
<delete dir="classes" failonerror="false"/>
<mkdir dir="classes"/>
<javac destdir="classes" includeAntRuntime="false" srcdir="src">
<withKotlin/>
</javac>
<jar destfile="hello.jar">
<fileset dir="classes"/>
</jar>
</target>
</project>
You can also specify the name of the module being compiled as the moduleName attribute:
<withKotlin moduleName="myModule"/>
<target name="build">
<kotlin2js src="root1" output="out.js"/>
</target>
</project>
<target name="build">
<kotlin2js src="root1" output="out.js" outputPrefix="prefix"
outputPostfix="postfix" sourcemap="true"/>
</target>
</project>
396
<project name="Ant Task Test" default="build">
<typedef resource="org/jetbrains/kotlin/ant/antlib.xml"
classpath="${kotlin.lib}/kotlin-ant.jar"/>
<target name="build">
<!-- out.meta.js will be created, which contains binary metadata -->
<kotlin2js src="root1" output="out.js" metaInfo="true"/>
</target>
</project>
References
Complete list of elements and attributes are listed below:
kotlinc Attributes
Name Description Required Default Value
output Destination directory or .jar file name Yes
classpath Compilation class path No
classpathref Compilation class path reference No
includeRuntime If output is a .jar file, whether Kotlin runtime No true
library is included in the jar
moduleName Name of the module being compiled No The name of the target (if
specified) or the project
kotlin2js Attributes
Name Description Required
output Destination file Yes
libraries Paths to Kotlin libraries No
outputPrefix Prefix to use for generated JavaScript files No
outputSuffix Suffix to use for generated JavaScript files No
sourcemap Whether sourcemap file should be generated No
metaInfo Whether metadata file with binary descriptors should be generated No
main Should compiler generated code call the main function No
To pass custom raw compiler arguments, you can use <compilerarg> elements with either
value or line attributes. This can be done within the <kotlinc> , <kotlin2js> , and
<withKotlin> task elements, as follows:
397
<kotlinc src="${test.data}/hello.kt" output="${temp}/hello.jar">
<compilerarg value="-Xno-inline"/>
<compilerarg line="-Xno-call-assertions -Xno-param-assertions"/>
<compilerarg value="-Xno-optimize"/>
</kotlinc>
The full list of arguments that can be used is shown when you run kotlinc -help .
398
Kotlin and OSGi
To enable Kotlin OSGi support you need to include kotlin-osgi-bundle instead of regular
Kotlin libraries. It is recommended to remove kotlin-runtime , kotlin-stdlib and kotlin-
reflect dependencies as kotlin-osgi-bundle already contains all of them. You also should
pay attention in case when external Kotlin libraries are included. Most regular Kotlin dependencies
are not OSGi-ready, so you shouldn't use them and should remove them from your project.
Maven
To include the Kotlin OSGi bundle to a Maven project:
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-osgi-bundle</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
To exclude the standard library from external libraries (notice that "star exclusion" works in Maven
3 only):
<dependency>
<groupId>some.group.id</groupId>
<artifactId>some.library</artifactId>
<version>some.library.version</version>
<exclusions>
<exclusion>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
Gradle
To include kotlin-osgi-bundle to a gradle project:
compile "org.jetbrains.kotlin:kotlin-osgi-bundle:$kotlinVersion"
To exclude default Kotlin libraries that comes as transitive dependencies you can use the following
approach:
dependencies {
compile (
[group: 'some.group.id', name: 'some.library', version: 'someversion'],
.....) {
exclude group: 'org.jetbrains.kotlin'
}
FAQ
399
Why not just add required manifest options to all Kotlin libraries
Even though it is the most preferred way to provide OSGi support, unfortunately it couldn't be
done for now due to so called "package split" issue that couldn't be easily eliminated and such a big
change is not planned for now. There is Require-Bundle feature but it is not the best option too
and not recommended to use. So it was decided to make a separate artifact for OSGi.
400
Compiler Plugins
For instance, when you use Spring, you don't need all the classes to be open, but only classes
annotated with speci c annotations like @Configuration or @Service . All-open allows to
specify such annotations.
We provide all-open plugin support both for Gradle and Maven with the complete IDE integration.
Note: For Spring you can use the kotlin-spring compiler plugin (see below).
Using in Gradle
Add the plugin artifact to the buildscript dependencies and apply the plugin:
buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
}
}
plugins {
id "org.jetbrains.kotlin.plugin.allopen" version "1.3.11"
}
Then specify the list of annotations that will make classes open:
allOpen {
annotation("com.my.Annotation")
// annotations("com.another.Annotation", "com.third.Annotation")
}
If the class (or any of its superclasses) is annotated with com.my.Annotation , the class itself and
all its members will become open.
@com.my.Annotation
annotation class MyFrameworkAnnotation
@MyFrameworkAnnotation
class MyClass // will be all-open
401
MyFrameworkAnnotation is annotated with the all-open meta-annotation
com.my.Annotation , so it becomes an all-open annotation as well.
Using in Maven
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<configuration>
<compilerPlugins>
<!-- Or "spring" for the Spring support -->
<plugin>all-open</plugin>
</compilerPlugins>
<pluginOptions>
<!-- Each annotation is placed on its own line -->
<option>all-open:annotation=com.my.Annotation</option>
<option>all-open:annotation=com.their.AnotherAnnotation</option>
</pluginOptions>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
Please refer to the "Using in Gradle" section above for the detailed information about how all-open
annotations work.
Spring support
If you use Spring, you can enable the kotlin-spring compiler plugin instead of specifying Spring
annotations manually. The kotlin-spring is a wrapper on top of all-open, and it behaves exactly the
same way.
buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version"
}
}
402
plugins {
id "org.jetbrains.kotlin.plugin.spring" version "1.3.11"
}
<compilerPlugins>
<plugin>spring</plugin>
</compilerPlugins>
Of course, you can use both kotlin-allopen and kotlin-spring in the same project.
Note that if you use the project template generated by the start.spring.io service, the kotlin-
spring plugin will be enabled by default.
Using in CLI
All-open compiler plugin JAR is available in the binary distribution of the Kotlin compiler. You can
attach the plugin by providing the path to its JAR le using the Xplugin kotlinc option:
-Xplugin=$KOTLIN_HOME/lib/allopen-compiler-plugin.jar
You can specify all-open annotations directly, using the annotation plugin option, or enable the
"preset". The only preset available now for all-open is spring .
-P plugin:org.jetbrains.kotlin.allopen:annotation=com.my.Annotation
-P plugin:org.jetbrains.kotlin.allopen:preset=spring
The generated constructor is synthetic so it can’t be directly called from Java or Kotlin, but it can be
called using re ection.
This allows the Java Persistence API (JPA) to instantiate a class although it doesn't have the zero-
parameter constructor from Kotlin or Java point of view (see the description of kotlin-jpa
plugin below).
Using in Gradle
403
The usage is pretty similar to all-open.
Add the plugin and specify the list of annotations that must lead to generating a no-arg constructor
for the annotated classes.
buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlin_version"
}
}
plugins {
id "org.jetbrains.kotlin.plugin.noarg" version "1.3.11"
}
noArg {
annotation("com.my.Annotation")
}
Enable invokeInitializers option if you want the plugin to run the initialization logic from the
synthetic constructor. Starting from Kotlin 1.1.3-2, it is disabled by default because of KT-18667
and KT-18668 which will be addressed in the future.
noArg {
invokeInitializers = true
}
Using in Maven
404
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<configuration>
<compilerPlugins>
<!-- Or "jpa" for JPA support -->
<plugin>no-arg</plugin>
</compilerPlugins>
<pluginOptions>
<option>no-arg:annotation=com.my.Annotation</option>
<!-- Call instance initializers in the synthetic constructor -->
<!-- <option>no-arg:invokeInitializers=true</option> -->
</pluginOptions>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-noarg</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
JPA support
As with the kotlin-spring plugin, kotlin-jpa is a wrapped on top of no-arg. The plugin speci es
@Entity, @Embeddable and @MappedSuperclass no-arg annotations automatically.
buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-noarg:$kotlin_version"
}
}
plugins {
id "org.jetbrains.kotlin.plugin.jpa" version "1.3.11"
}
<compilerPlugins>
<plugin>jpa</plugin>
</compilerPlugins>
Using in CLI
405
As with all-open, add the plugin JAR le to the compiler plugin classpath and specify annotations or
presets:
-Xplugin=$KOTLIN_HOME/lib/noarg-compiler-plugin.jar
-P plugin:org.jetbrains.kotlin.noarg:annotation=com.my.Annotation
-P plugin:org.jetbrains.kotlin.noarg:preset=jpa
Here is an example:
@SamWithReceiver
public interface TaskRunner {
void run(Task task);
}
println("$name is started")
context.executeTask(this)
println("$name is finished")
}
}
Using in Gradle
The usage is the same to all-open and no-arg, except the fact that sam-with-receiver does not have
any built-in presets, and you need to specify your own list of special-treated annotations.
buildscript {
dependencies {
classpath "org.jetbrains.kotlin:kotlin-sam-with-receiver:$kotlin_version"
}
}
samWithReceiver {
annotation("com.my.Annotation")
}
Using in Maven
406
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${kotlin.version}</version>
<configuration>
<compilerPlugins>
<plugin>sam-with-receiver</plugin>
</compilerPlugins>
<pluginOptions>
<option>
sam-with-receiver:annotation=com.my.SamWithReceiver
</option>
</pluginOptions>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-sam-with-receiver</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
Using in CLI
Just add the plugin JAR le to the compiler plugin classpath and specify the list of sam-with-receiver
annotations:
-Xplugin=$KOTLIN_HOME/lib/sam-with-receiver-compiler-plugin.jar
-P plugin:org.jetbrains.kotlin.samWithReceiver:annotation=com.my.SamWithReceiver
407
Code Style Migration Guide
Unfortunately, the code formatter built into IntelliJ IDEA had to work long before this document
was released and now has a default setup that produces di erent formatting from what is now
recommended.
It may seem a logical next step to remove this obscurity by switching the defaults in IntelliJ IDEA
and make formatting consistent with the Kotlin Coding Conventions. But this would mean that all
the existing Kotlin projects will have a new code style enabled the moment the Kotlin plugin is
installed. Not really the expected result for plugin update, right?
— Enable the o cial code style formatting by default starting from Kotlin 1.3 and only for new
projects (old formatting can be enabled manually)
— Authors of existing projects may choose to migrate to the Kotlin Coding Conventions
— Authors of existing projects may choose to explicitly declare using the old code style in a project
(this way the project won't be a ected by switching to the defaults in the future)
— Switch to the default formatting and make it consistent with Kotlin Coding Conventions in Kotlin
1.4
In practice, quite a bit of code is a ected, so this can be considered a major code style update.
Changing formatting in an existing project is a far more demanding task, and should probably be
started with discussing all the caveats with the team.
408
The main disadvantage of changing the code style in an existing project is that the blame/annotate
VCS feature will point to irrelevant commits more often. While each VCS has some kind of way to
deal with this problem ("Annotate Previous Revision" can be used in IntelliJ IDEA), it's important to
decide if a new style is worth all the e ort. The practice of separating reformatting commits from
meaningful changes can help a lot with later investigations.
Also migrating can be harder for larger teams because committing a lot of les in several
subsystems may produce merging con icts in personal branches. And while each con ict resolution
is usually trivial, it's still wise to know if there are large feature branches currently in work.
In general, for small projects, we recommend converting all the les at once.
For medium and large projects the decision may be tough. If you are not ready to update many
les right away you may decide to migrate module by module, or continue with gradual migration
for modi ed les only.
In order to share those changes for all project developers .idea/codeStyle folder have to be
committed to VCS.
If an external build system is used for con guring the project, and it's been decided not to share
.idea/codeStyle folder, Kotlin Coding Conventions can be forced with an additional property:
In Gradle
Add kotlin.code.style=o cial property to the gradle.properties le at the project root and
commit the le to VCS.
In Maven
<properties>
<kotlin.code.style>official</kotlin.code.style>
</properties>
Warning: having the kotlin.code.style option set may modify the code style scheme during a
project import and may change the code style settings.
After updating your code style settings, activate “Reformat Code” in the project view on the desired
scope.
409
For a gradual migration, it's possible to enable the "File is not formatted according to project settings"
inspection. It will highlight the places that should be reformatted. After enabling the "Apply only to
modi ed les" option, inspection will show formatting problems only in modi ed les. Such les are
probably going to be committed soon anyway.
In order to share the changes across the project developers .idea/codeStyle folder, it has to
be committed to VCS. Alternatively kotlin.code.style=obsolete can be used for projects con gured
with Gradle or Maven.
410
Evolution
Kotlin Evolution
Kotlin is designed to be a pragmatic tool for programmers. When it comes to language evolution,
its pragmatic nature is captured by the following principles:
As this is key to understanding how Kotlin is moving forward, let's expand on these principles.
Keeping the Language Modern. We acknowledge that systems accumulate legacy over time. What
had once been cutting-edge technology can be hopelessly outdated today. We have to evolve the
language to keep it relevant to the needs of the users and up-to-date with their expectations. This
includes not only adding new features, but also phasing out old ones that are no longer
recommended for production use and have altogether become legacy.
Comfortable Updates. Incompatible changes, such as removing things from a language, may lead
to painful migration from one version to the next if carried out without proper care. We will always
announce such changes well in advance, mark things as deprecated and provide automated
migration tools before the change happens. By the time the language is changed we want most of
the code in the world to be already updated and thus have no issues migrating to the new version.
Feedback Loop. Going through deprecation cycles requires signi cant e ort, so we want to
minimize the number of incompatible changes we'll be making in the future. Apart from using our
best judgement, we believe that trying things out in real life is the best way to validate a design.
Before casting things in stone we want them battle-tested. This is why we use every opportunity to
make early versions of our designs available in production versions of the language, but with
experimental status. Experimental features are not stable, they can be changed at any time, and the
users that opt into using them do so explicitly to indicate that they are ready to deal with the future
migration issues. These users provide invaluable feedback that we gather to iterate on the design
and make it rock-solid.
411
Incompatible Changes
If, upon updating from one version to another, some code that used to work doesn't work any
more, it is an incompatible change in the language (sometimes referred to as "breaking change").
There can be debates as to what "doesn't work any more" means precisely in some cases, but it
de nitely includes the following:
— Code that compiled and ran ne is now rejected with an error (at compile or link time). This
includes removing language constructs and adding new restrictions.
— Code that executed normally is now throwing an exception.
The less obvious cases that belong to the "grey area" include handling corner cases di erently,
throwing an exception of a di erent type than before, changing behavior observable only through
re ection, changes in undocumented/unde ned behavior, renaming binary artifacts, etc.
Sometimes such changes are very important and a ect migration experience dramatically,
sometimes they are insigni cant.
The principles of Keeping the Language Modern and Comfortable Updates suggest that
incompatible changes are sometimes necessary, but they should be introduced carefully. Our goal
is to make the users aware of upcoming changes well in advance to let them migrate their code
comfortably.
Ideally, every incompatible change should be announced through a compile-time warning reported
in the problematic code (usually referred to as a deprecation warning) and accompanied with
automated migration aids. So, the ideal migration work ow goes as follows:
In practice some changes can't be accurately detected at compile time, so no warnings can be
reported, but at least the users will be noti ed through Release notes of version A that a change is
coming in version B.
412
Compilers are complicated software and despite the best e ort of their developers they have bugs.
The bugs that cause the compiler itself to fail or report spurious errors or generate obviously
failing code, though annoying and often embarrassing, are easy to x, because the xes do not
constitute incompatible changes. Other bugs may cause the compiler to generate incorrect code
that does not fail: e.g. by missing some errors in the source or simply generating wrong
instructions. Fixes of such bugs are technically incompatible changes (some code used to compile
ne, but now it won't any more), but we are inclined to xing them as soon as possible to prevent
the bad code patterns from spreading across user code. In our opinion, this serves the principle of
Comfortable Updates, because fewer users have a chance of encountering the issue. Of course, this
applies only to bugs that are found soon after appearing in a released version.
Decision Making
JetBrains, the original creator of Kotlin, is driving its progress with the help of the community and
in accord with the Kotlin Foundation.
All changes to the Kotlin Programming Language are overseen by the Lead Language Designer
(currently Andrey Breslav). The Lead Designer has the nal say in all matters related to language
evolution. Additionally, incompatible changes to fully stable components have to be approved to by
the Language Committee designated under the Kotlin Foundation (currently comprised of Je rey
van Gogh, William R. Cook and Andrey Breslav).
The Language Committee makes nal decisions on what incompatible changes will be made and
what exact measures should be taken to make user updates comfortable. In doing so, it relies on a
set of guidelines available here.
Incremental releases bring updates in the tooling (often including features), performance
improvements and bug xes. We try to keep such versions compatible with each other, so changes
to the compiler are mostly optimizations and warning additions/removals. Experimental features
may, of course, be added, removed or changed at any time.
Feature releases often add new features and may remove or change previously deprecated ones.
Feature graduation from experimental to stable also happens in feature releases.
EAP Builds
413
Before releasing stable versions, we usually publish a number of preview builds dubbed EAP (for
"Early Access Preview") that let us iterate faster and gather feedback from the community. EAPs of
feature releases usually produce binaries that will be later rejected by the stable compiler to make
sure that possible bugs in the binary format survive no longer than the preview period. Final
Release Candidates normally do not bear this limitation.
Experimental features
According to the Feedback Loop principle described above, we iterate on our designs in the open
and release versions of the language where some features have the experimental status and are
supposed to change. Experimental features can be added, changed or removed at any point and
without warning. We make sure that experimental features can't be used accidentally by an
unsuspecting user. Such features usually require some sort of an explicit opt-in either in the code
or in the project con guration.
Experimental features usually graduate to the stable status after some iterations.
To check the stability status of di erent components of Kotlin (Kotlin/JVM, JS, Native, various
libraries, etc), please consult this link.
Libraries
A language is nothing without its ecosystem, so we pay extra attention to enabling smooth library
evolution.
Ideally, a new version of a library can be used as a "drop-in replacement" for an older version. This
means that upgrading a binary dependency should not break anything, even if the application is
not recompiled (this is possible under dynamic linking).
On the one hand, to achieve this, the compiler has to provide certain ABI stability guarantees under
the constraints of separate compilation. This is why every change in the language is examined from
the point of view of binary compatibility.
On the other hand, a lot depends on the library authors being careful about which changes are safe
to make. Thus it's very important that library authors understand how source changes a ect
compatibility and follow certain best practices to keep both APIs and ABIs of their libraries stable.
Here are some assumptions that we make when considering language changes from the library
evolution standpoint:
— Library code should always specify return types of public/protected functions and properties
explicitly thus never relying on type inference for public API. Subtle changes in type inference
may cause return types to change inadvertently, leading to binary compatibility issues.
— Overloaded functions and properties provided by the same library should do essentially the
same thing. Changes in type inference may result in more precise static types to be known at
414
call sites causing changes in overload resolution.
Library authors can use the @Deprecated and @Experimental annotations to control the evolution
of their API surface. Note that @Deprecated(level=HIDDEN) can be used to preserve binary
compatibility even for declarations removed from the API.
Also, by convention, packages named "internal" are not considered public API. All API residing in
packages named "experimental" is considered experimental and can change at any moment.
We evolve the Kotlin Standard Library (kotlin-stdlib) for stable platforms according to the principles
stated above. Changes to the contracts for its API undergo the same procedures as changes in the
language itself.
Compiler Keys
Command line keys accepted by the compiler are also a kind of public API, and they are subject to
the same considerations. Supported ags (those that don't have the "-X" or "-XX" pre x) can be
added only in feature releases and should be properly deprecated before removing them. The "-X"
and "-XX" ags are experimental and can be added and removed at any time.
Compatibility Tools
As legacy features get removed and bugs xed, the source language changes, and old code that has
not been properly migrated may not compile any more. The normal deprecation cycle allows a
comfortable period of time for migration, and even when it's over and the change ships in a stable
version, there's still a way to compile unmigrated code.
Compatibility ags
We provide the -language-version and -api-version ags that make a new version emulate the
behaviour of an old one, for compatibility purposes. Normally, at least one previous version is
supported. This e ectively leaves a time span of two full feature release cycles for migration (which
usually amounts to about two years). Using an older kotlin-stdlib or kotlin-re ect with a newer
compiler without specifying compatibility ags is not recommended, and the compiler will report a
warning when this happens.
Actively maintained code bases can bene t from getting bug xes ASAP, without waiting for a full
deprecation cycle to complete. Currently such project can enable the -progressive ag and get such
xes enabled even in incremental releases.
All ags are available on the command line as well as Gradle and Maven.
Unlike sources that can be xed by hand in the worst case, binaries are a lot harder to migrate, and
this makes backwards compatibility very important in the case of binaries. Incompatible changes to
binaries can make updates very uncomfortable and thus should be introduced with even more
care than those in the source language syntax.
415
For fully stable versions of the compiler the default binary compatibility protocol is the following:
— All binaries are backwards compatible, i.e. a newer compiler can read older binaries (e.g. 1.3
understands 1.0 through 1.2),
— Older compilers reject binaries that rely on new features (e.g. a 1.0 compiler rejects binaries
that use coroutines).
— Preferably (but we can't guarantee it), the binary format is mostly forwards compatible with the
next feature release, but not later ones (in the cases when new features are not used, e.g. 1.3
can understand most binaries from 1.4, but not 1.5).
This protocol is designed for comfortable updates as no project can be blocked from updating its
dependencies even if it's using a slightly outdated compiler.
Please note that not all target platforms have reached this level of stability (but Kotlin/JVM has).
416
Stability of Di erent Components
There can be di erent modes of stability depending of how quickly a component is evolving:
— Moving fast (MF): no compatibility should be expected between even incremental releases, any
functionality can be added, removed or changed without warning.
— Stable Incremental Releases (SIR): incremental releases are fully compatible, only
optimizations and bug xes happen. Any changes can be made in a feature release.
— Fully Stable (FS): incremental releases are fully compatible, only optimizations and bug xes
happen. Feature releases are backwards compatible.
Source and binary compatibility may have di erent modes for the same component, e.g. the
source language can reach full stability before the binary format stabilizes, or vice versa.
The provisions of the Kotlin evolution policy fully apply only to components that have reached Full
Stability (FS). From that point on incompatible changes have to be approved by the Language
Committee.
417
Compatibility Guide for Kotlin 1.3
Keeping the Language Modern and Comfortable Updates are among the fundamental principles in
Kotlin Language Design. The former says that constructions which obstruct language evolution
should be removed, and the latter says that this removal should be well-communicated
beforehand to make code migration as smooth as possible.
While most of the language changes were already announced through other channels, like update
changelogs or compiler warnings, this document summarizes them all, providing a complete
reference for migration from Kotlin 1.2 to Kotlin 1.3
Basic terms
In this document we introduce several kinds of compatibility:
— Source: source-incompatible change stops code that used to compile ne (without errors or
warnings) from compiling anymore
— Binary: two binary artifacts are said to be binary-compatible if interchanging them doesn't lead
to loading or linkage errors
— Behavioral: a change is said to be behavioral-incompatible if one and the same program
demonstrates di erent behavior before and after applying the change
One has to remember that those de nitions are given only for pure Kotlin. Compatibility of Kotlin
code from the other languages perspective (e.g. from Java) is out of the scope of this document.
Issue: KT-19532
Component: Kotlin/JVM
Short summary: evaluation order with respect to class initialization is changed in 1.3
Deprecation cycle:
418
Issue: KT-25287
Component: Kotlin/JVM
Deprecation cycle:
Issue: KT-19628
Deprecation cycle:
— <1.2: compilation errors in getter-target annotations were not reported, causing incorrect
code to be compiled ne.
— 1.2.x: errors reported only by tooling, the compiler still compiles such code without any
warnings
— >=1.3: errors reported by the compiler too, causing erroneous code to be rejected
419
Issue: KT-20830
Component: Kotlin/JVM
Short summary: nullability assertions for Java-types annotated with not-null annotations will
be generated more aggressively, causing code which passes null here to fail faster.
Deprecation cycle:
— <1.3: the compiler could miss such assertions when type inference was involved, allowing
potential null propagation during compilation against binaries (see Issue for details).
— >=1.3: the compiler generates missed assertions. This can case code which was
(erroneously) passing nulls here fail faster.
-XXLanguage:-StrictJavaNullabilityAssertions can be used to temporarily
return to the pre-1.3 behavior. Support for this ag will be removed in the next major
release.
Issue: KT-20772
Short summary: a smartcast on a member of one enum entry will be correctly applied to only
this enum entry
Deprecation cycle:
— <1.3: a smartcast on a member of one enum entry could lead to an unsound smartcast on
the same member of other enum entries.
— >=1.3: smartcast will be properly applied only to the member of one enum entry.
-XXLanguage:-SoundSmartcastForEnumEntries will temporarily return old behavior.
Support for this ag will be removed in the next major release.
420
Issue: KT-16681
Short summary: reassignment of the backing eld of val-property in its getter is now
prohibited
Deprecation cycle:
— <1.2: Kotlin compiler allowed to modify backing eld of val in its getter. Not only it violates
Kotlin semantic, but also generates ill-behaved JVM bytecode which reassigns final eld.
— 1.2.X: deprecation warning is reported on code which reassigns backing eld of val
Issue: KT-21354
Component: Kotlin/JVM
Short summary: if an expression in for-loop range is a local variable updated in a loop body,
this change a ects loop execution. This is inconsistent with iterating over other containers,
such as ranges, character sequences, and collections.
Deprecation cycle:
— <1.2: described code patterns are compiled ne, but updates to local variable a ect loop
execution
— 1.2.X: deprecation warning reported if a range expression in a for-loop is an array-typed
local variable which is assigned in a loop body
— 1.3: change behavior in such cases to be consistent with other containers
421
Issue: KT-16310
Short summary: since Kotlin 1.3, nested classi ers (classes, object, interfaces, annotation
classes, enum classes) in enum entries are prohibited
Deprecation cycle:
— <1.2: nested classi ers in enum entries are compiled ne, but may fail with exception at
runtime
— 1.2.X: deprecation warnings reported on the nested classi ers
— >=1.3: deprecation warnings elevated to errors
Issue: KT-19618
Short summary: since Kotlin 1.3, data classes are prohibited to override copy()
Deprecation cycle:
— <1.2: data classes overriding copy() are compiled ne but may fail at runtime/expose
strange behavior
— 1.2.X: deprecation warnings reported on data classes overriding copy()
Inner classes inheriting Throwable that capture generic parameters from the outer
class
422
Issue: KT-17981
Short summary: since Kotlin 1.3, inner classes are not allowed to inherit Throwable
Deprecation cycle:
— <1.2: inner classes inheriting Throwable are compiled ne. If such inner classes happen to
capture generic parameters, it could lead to strange code patterns which fail at runtime.
— 1.2.X: deprecation warnings reported on inner classes inheriting Throwable
Short summary: since Kotlin 1.3, rules of visibility by short names are stricter for complex
class hierarchies involving companion objects and nested classi ers.
Deprecation cycle:
423
Issue: KT-23153
Short summary: since Kotlin 1.3, setting non-constant values as vararg annotation parameters
is prohibited
Deprecation cycle:
— <1.2: the compiler allows to pass non-constant value for vararg annotation parameter, but
actually drops that value during bytecode generation, leading to non-obvious behavior
— 1.2.X: deprecation warnings reported on such code patterns
— >=1.3: deprecation warnings elevated to errors
Issue: KT-23277
Short summary: since Kotlin 1.3 local annotation classes are not supported
Deprecation cycle:
424
Issue: KT-22517
Short summary: since Kotlin 1.3 smartcasts on local delegated properties are not allowed
Deprecation cycle:
— <1.2: the compiler allowed to smartcast local delegated property, which could lead to
unsound smartcast in case of ill-behaved delegates
— 1.2.X: smartcasts on local delegated properries are reported as deprecated (the compiler
issues warnings)
— >=1.3: deprecation warnings elevated to errors
Issues: KT-24197
Short summary: since Kotlin 1.3 declaration of mod operator is prohibited, as well as calls
which resolve to such declarations
Deprecation cycle:
— 1.1.X, 1.2.X: report warnings on declarations of operator mod, as well as on calls which
resolve to it
— 1.3.X: elevate warnings to error, but still allow to resolve to operator mod declarations
425
Issues: KT-20588, KT-20589. See also KT-20171
Short summary: in Kotlin 1.3, assigning single element to vararg is deprecated and should be
replaced with consecutive spread and array construction.
Deprecation cycle:
— <1.2: assigning one value element to vararg in named form compiles ne and is treated as
assigning single element to array, causing non-obvious behavior when assigning array to
vararg
— 1.2.X: deprecation warnings are reported on such assignments, users are suggested to
switch to consecutive spread and array construction.
— 1.3.X: warnings are elevated to errors
— >= 1.4: change semantic of assigning single element to vararg, making assignment of array
equivalent to the assignment of a spread of an array
Issue: KT-13762
Short summary: since Kotlin 1.3, only SOURCE retention is allowed for annotations with target
EXPRESSION
Deprecation cycle:
— <1.2: annotations with target EXPRESSION and retention other than SOURCE are allowed,
but silently ignored at use-sites
— 1.2.X: deprecation warnings are reported on declarations of such annotations
— >=1.3: warnings are elevated to errors
426
Issue: KT-9580
Short summary: since Kotlin 1.3, error about wrong annotation target will be properly
reported when annotation with target PARAMETER is applied to parameter's type
Deprecation cycle:
— <1.2: aforementioned code patterns are compiled ne; annotations are silently ignored and
not present in the bytecode
— 1.2.X: deprecation warnings are reported on such usages
— >=1.3: warnings are elevated to errors
Issue: KT-19489
Short summary: since Kotlin 1.3, ensure that the toIndex argument of
Array.copyOfRange, which represents the exclusive end of the range being copied, is not
greater than the array size and throw IllegalArgumentException if it is.
Deprecation cycle:
— <1.3: in case toIndex in the invocation of Array.copyOfRange is greater than the array
size, the missing elements in range ll be lled with nulls, violating soundness of the Kotlin
type system.
— >=1.3: check that toIndex is in the array bounds, and throw exception if it isn't
427
Issue: KT-17176
Short summary: since Kotlin 1.3, prohibit step value for integer progressions being the
minimum negative value of its integer type (Long or Int), so that calling
IntProgression.fromClosedRange(0, 1, step = Int.MIN_VALUE) will throw
IllegalArgumentException
Deprecation cycle:
Issue: KT-16097
Short summary: since Kotlin 1.3, make sure index, count and similar methods do not
over ow for long sequences. See the Issue for the full list of a ected methods.
Deprecation cycle:
— <1.3: calling such methods on very long sequences could produce negative results due to
integer over ow
— >=1.3: detect over ow in such methods and throw exception immediately
428
Issue: KT-21049
Short summary: since Kotlin 1.3, unify behavior of split method by empty match regex
across all platforms
Deprecation cycle:
— <1.3: behavior of described calls is di erent when comparing JS, JRE 6, JRE 7 versus JRE 8+
— >=1.3: unify behavior across the platforms
Issue: KT-23799
Component: other
Short summary: Kotlin 1.3 discontinues the following deprecated binary artifacts:
Deprecation cycle:
— 1.2.X: the artifacts were marked as deprecated, the compiler reported warning on usage of
those artifacts
— >=1.3: the artifacts are discontinued
Annotations in stdlib
429
Issue: KT-21784
Deprecation cycle:
430
FAQ
FAQ
What is Kotlin?
Kotlin is an OSS statically typed programming language that targets the JVM, Android, JavaScript and
Native. It’s developed by JetBrains. The project started in 2010 and was open source from very
early on. The rst o cial 1.0 release was in February 2016.
Is Kotlin free?
Yes. Kotlin is free, has been free and will remain free. It is developed under the Apache 2.0 license
and the source code is available on GitHub.
Kotlin has both object-oriented and functional constructs. You can use it in both OO and FP styles,
or mix elements of the two. With rst-class support for features such as higher-order functions,
function types and lambdas, Kotlin is a great choice if you’re doing or exploring functional
programming.
What advantages does Kotlin give me over the Java programming language?
Kotlin is more concise. Rough estimates indicate approximately a 40% cut in the number of lines of
code. It’s also more type-safe, e.g. support for non-nullable types makes applications less prone to
NPE’s. Other features including smart casting, higher-order functions, extension functions and
lambdas with receivers provide the ability to write expressive code as well as facilitating creation of
DSL.
431
Yes. Kotlin is 100% interoperable with the Java programming language and major emphasis has
been placed on making sure that your existing codebase can interact properly with Kotlin. You can
easily call Kotlin code from Java and Java code from Kotlin. This makes adoption much easier and
lower-risk. There’s also an automated Java-to-Kotlin converter built into the IDE that simpli es
migration of existing code.
Kotlin can be used for any kind of development, be it server-side, client-side web and Android. With
Kotlin/Native currently in the works, support for other platforms such as embedded systems,
macOS and iOS is coming. People are using Kotlin for mobile and server-side applications, client-
side with JavaScript or JavaFX, and data science, just to name a few possibilities.
Yes. Kotlin is supported as a rst-class language on Android. There are hundreds of applications
already using Kotlin for Android, such as Basecamp, Pinterest and more. For more information
check out the resource on Android development.
Yes. Kotlin is 100% compatible with the JVM and as such you can use any existing frameworks such
as Spring Boot, vert.x or JSF. In addition there are speci c frameworks written in Kotlin such as
Ktor. For more information check out the resource on server-side development.
Yes. In addition to using for backend web, you can also use Kotlin/JS for client-side web. Kotlin can
use de nitions from De nitelyTyped to get static typing for common JavaScript libraries, and it is
compatible with existing module systems such as AMD and CommonJS. For more information check
out the resource on client-side development.
Yes. You can use any Java UI framework such as JavaFx, Swing or other. In addition there are Kotlin
speci c frameworks such as TornadoFX.
Kotlin/Native is currently in the works. It compiles Kotlin to native code that can run without a VM.
There is a Technology Preview released but it is not production-ready yet, and doesn’t yet target all
the platforms that we plan to support for 1.0. For more information check out the blog post
announcing Kotlin/Native.
432
Kotlin is supported by all major Java IDEs including IntelliJ IDEA, Android Studio, Eclipse and
NetBeans. In addition, a command line compiler is available and provides straightforward support
for compiling and running applications.
On the JVM side, the main build tools include Gradle, Maven, Ant, and Kobalt. There are also some
build tools available that target client-side JavaScript.
When targeting the JVM, Kotlin produces Java compatible bytecode. When targeting JavaScript,
Kotlin transpiles to ES5.1 and generates code which is compatible with module systems including
AMD and CommonJS. When targeting native, Kotlin will produce platform-speci c code (via LLVM).
No. Kotlin lets you choose between generating Java 6 and Java 8 compatible bytecode. More
optimal byte code may be generated for higher versions of the platform.
Is Kotlin hard?
Kotlin is inspired by existing languages such as Java, C#, JavaScript, Scala and Groovy. We've tried to
ensure that Kotlin is easy to learn, so that people can easily jump on board, reading and writing
Kotlin in a matter of days. Learning idiomatic Kotlin and using some more of its advanced features
can take a little longer, but overall it is not a complicated language.
There are too many companies using Kotlin to list, but some more visible companies that have
publicly declared usage of Kotlin, be this via blog posts, GitHub repositories or talks include Square,
Pinterest, Basecamp or Corda.
Kotlin is primarily developed by a team of engineers at JetBrains (current team size is 40+). The
lead language designer is Andrey Breslav. In addition to the core team, there are also over 100
external contributors on GitHub.
The best place to start is this website. From there you can download the compiler, try it online as
well as get access to resources, reference documentation and tutorials.
433
There are already a number of books available for Kotlin, including Kotlin in Action which is by
Kotlin team members Dmitry Jemerov and Svetlana Isakova, Kotlin for Android Developers targeted
at Android developers.
There are a few courses available for Kotlin, including a Pluralsight Kotlin Course by Kevin Jones, an
O’Reilly Course by Hadi Hariri and an Udemy Kotlin Course by Peter Sommerho .
There are also many recordings of Kotlin talks available on YouTube and Vimeo.
Yes. Kotlin has a very vibrant community. Kotlin developers hang out on the Kotlin forums,
StackOver ow and more actively on the Kotlin Slack (with close to 20000 members as of October
2018).
Yes. There are many User Groups and Meetups now focused exclusively around Kotlin. You can
nd a list on the web site. In addition there are community organised Kotlin Nights events around
the world.
Yes. The o cial annual KotlinConf is hosted by JetBrains. It has taken place in San-Francisco in 2017
and in Amsterdam in 2018. Kotlin is also being covered in di erent conferences worldwide. You
can nd a list of upcoming talks on the web site.
Yes. The most active Kotlin account is on Twitter. There is also a Google+ group.
The web site has a bunch of online resources, including Kotlin Digests by community members, a
newsletter, a podcast and more.
Logos can be downloaded here. Please follow simple rules in the guidelines.pdf inside the
archive.
434
Comparison to Java Programming Language
435
— Coroutines
436
437