Kotlin Docs
Kotlin Docs
Table of Contents
Overview 5
Multiplatform Programming 12
Standard library 33
Tooling 35
Getting Started 36
Basic Syntax 36
Idioms 42
Coding Conventions 47
Basics 62
Basic Types 62
Packages 69
Interfaces 85
Visibility Modifiers 87
Extensions 89
Data Classes 93
Sealed Classes 95
Generics 96
Delegation 111
Functions 118
2
Higher-Order Functions and Lambdas 123
Other 143
Ranges 147
Equality 154
Exceptions 162
Annotations 164
Reflection 168
Reference 178
Grammar 182
Notation 182
Semicolons 182
Syntax 182
JavaScript 208
Example 219
Native 221
3
Advanced topics 226
Platform libraries 228
Coroutines 250
Supervision 282
Tools 293
Evolution 324
FAQ 329
FAQ 329
4
Overview
Using Kotlin for Server-side Development
Kotlin is a great fit 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 benefits 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 offers framework-specific 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 first steps. Kotlin Koans offer 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, offers 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
offering 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.
To deploy Kotlin applications on Heroku, you can follow the official 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.
5
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.
6
Using Kotlin for Android Development
Kotlin is a great fit 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 file.
— Compilation Time: Kotlin supports efficient 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 first steps. Kotlin Koans offer 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 difference 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.
— 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 files 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 first 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.
7
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 file 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 definitions from the Definitely Typed type definitions
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 specifically 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 configuration.
Kotlin is compatible with CommonJS, AMD and UMD, making interaction with different module systems straightforward.
8
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
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
9
— Swift/Objective-C interop
Recommended tutorials:
Example Projects
— Kotlin/Native sources and examples
— KotlinConf app
— KotlinConf Spinner app
10
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 fluid from the user's perspective, but scalable when
needed.
There are many approaches to this problem, and in Kotlin we take a very flexible one by providing Coroutine support at the
language level and delegating most of the functionality to libraries, much inline 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
— kotlinx.coroutines Examples and Sources
— KotlinConf app
11
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 benefit of reuse for
code and expertise, saving the effort 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:
It expects the targets to provide platform-specific implementations for writeLogMessage , and the common code can now use
this declaration without any consideration of how it is implemented.
On the JVM, one could provide an implementation that writes the log to the standard output:
In the JavaScript world, a completely different 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 flexible, and we'll keep working on it to make project configuration straightforward.
Multiplatform Libraries
12
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 differently 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 benefits 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
Recommended tutorials:
Example Projects
— KotlinConf app
— KotlinConf Spinner app
13
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 specific programming paradigm or concurrency library.
A coroutine is effectively 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 different thread) when the operation being awaited
completes.
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:
14
val seq = buildSequence {
for (i in 1..5) {
// yield a square of i
yield(i * i)
}
// yield a range
yieldAll(26..28)
}
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 final 1.1 release.
Type aliases
A type alias allows you to define 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 specific object instance.
Previously this could only be expressed with a lambda. Here's an example:
Kotlin 1.1 removes some of the restrictions on sealed and data classes that were present in Kotlin 1.0. Now you can define
subclasses of a top-level sealed class on the top level in the same file, and not just as nested classes of the sealed class. Data
classes can now extend other classes. This can be used to define a hierarchy of expression classes nicely and cleanly:
15
sealed class Expr
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:
Just as in Java 8, Kotlin now allows to use underscores in numeric literals to separate groups of digits:
For properties with the getter defined as an expression body, the property type can now be omitted:
16
Inline property accessors
You can now mark property accessors with the inline modifier if the properties don't have a backing field. Such accessors
are compiled in the same way as inline functions.
You can also mark the entire property as inline - then the modifier is applied to both accessors.
You can now use the delegated property syntax with local variables. One possible use is defining a lazily evaluated local
variable:
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.
17
enum class RGB { RED, GREEN, BLUE }
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> .
In Kotlin 1.1, you can restrict that, so that only methods defined on the implicit receiver of td will be available inside the
lambda passed to td . You do that by defining 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.
Also integer conversion functions, like Int.toString() , String.toInt() , String.toIntOrNull() , each got an overload
with radix parameter, which allows to specify the base of conversion (2 to 36).
onEach()
onEach is a small, but useful extension function for collections and sequences, which allows to perform some action, possibly
with side-effects, 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))) }
18
also is like apply : it takes the receiver, does some action on it, and returns that receiver. The difference 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:
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 fills 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.
These functions can be used to find 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.
19
val list1 = listOf("a", "b")
val list2 = listOf("x", "y", "z")
val minSize = minOf(list1.size, list2.size)
val longestList = maxOf(list1, list2, compareBy { it.size })
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.
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.
20
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 fields. This change improves
performance, but can lead to new race conditions in some rare usage scenarios. If you're affected by this, you need to provide
your own synchronization for accessing the variables.
javax.script support
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 reflection interfaces (such as KClass ) are part of the Kotlin standard library, not kotlin-
reflect , and are not affected 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 defined 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 minifiers,
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 modifier. (In Kotlin 1.0, the @native annotation was used instead.) Unlike the JVM target, the JS one permits to
use external modifier with classes and properties. For example, here's how you can declare the DOM Node class:
21
external class Node {
val firstChild: Node
// etc
}
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 configured to use.
22
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 specific 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 specific
platform, as well as other platform-dependent code.
— A regular module targets a specific platform and can either be a dependency of platform modules or depend on platform
modules.
When you compile a multiplatform project for a specific platform, the code for both the common and platform-specific parts is
generated.
A key feature of the multiplatform project support is the possibility to express dependencies of common code on platform-
specific parts through expected and actual declarations. An expected declaration specifies 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)
}
See the documentation for details and steps to build a multiplatform project.
23
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 modifier 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 defined later:
You can now check whether a lateinit var has been initialized using isInitialized on the property reference:
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 specific 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:
24
Smart cast improvements
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 modified 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.
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 fixes 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 flag -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 conflict has become deprecated with a warning in Kotlin 1.2 and will be an error in Kotlin 1.3.
Inside enum entries, defining 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))
25
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.
Mutating the backing field 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 files
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
different 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 buffering 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")
26
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:
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 floating point numbers from the bit representation.
The kotlin.text.Regex class has become Serializable and can now be used in serializable hierarchies.
The Closeable.use function calls Throwable.addSuppressed when an exception is thrown during closing the resource after
some other exception.
JVM Backend
27
Constructor calls normalization
Ever since version 1.0, Kotlin supported expressions with complex control flow, such as try-catch expressions and inline
function calls. Such code is valid according to the Java Virtual Machine specification. 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 affect 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 flow in variables, instead of evaluating them
directly inside the call arguments. It’s similar to -Xnormalize-constructor-calls=enable .
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.
Calling x.equals(null) on a platform type that is mapped to a Java primitive ( Int! , Boolean! , Short !, Long! , Float! ,
Double! , Char! ) incorrectly returned true when x was null. Starting with Kotlin 1.2, calling x.equals(...) on a null value
of a platform type throws an NPE (but x == ... does not).
To return to the pre-1.2 behavior, pass the flag -Xno-exception-on-explicit-equals-for-boxed-null to the compiler.
Breaking change: x for platform null escaping through an inlined extension receiver
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.
To switch to the old behavior, pass the fallback flag -Xno-receiver-assertions to the compiler.
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
}
28
What's Coming in Kotlin 1.3
Coroutines release
After some long and extensive battle testing, the coroutines API is now released! It means that from Kotlin 1.3 the API will
remain stable on par with other released features. Check out the new coroutines overview page
Kotlin 1.3 introduces callable references on suspend-functions and support of Coroutines in the Reflection 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 flexibility, and to
make sharing common code easier. Also, Kotlin/Native is now supported as one of the targets! Find all the details here
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:
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:
29
fun synchronize(lock: Any?, block: () -> Unit) {
// It tells compiler:
// "This function will invoke 'block' here and now, and exactly one time"
contract { callsInPlace(block, EXACTLY_ONCE) }
}
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 benefit from the improved analysis right now without any additional opt-ins:
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
30
With Kotlin 1.3, it is possible to mark members of a companion object of interfaces with annotations @JvmStatic and
@JvmField . In the classfile, such members will be lifted to the corresponding interface and marked as static
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!")
}
Kotlin 1.3 relaxes this limitation and adds support for functions with bigger arity:
31
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 fine, 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 fixes 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 fixes in language semantics can arrive immediately. All these fixes 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 fine 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 fixes
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:
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
32
— kotlin.ULong : an unsigned 64-bit integer, ranges from 0 to 2^64 - 1
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
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
specific solutions, like java.util.Random on JVM. This release fixes this issue by introducing the class
kotlin.random.Random , which is available on all platforms:
isNullOrEmpty/orEmpty extensions
33
isNullOrEmpty and orEmpty extensions for some types are already present in stdlib . The first 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.
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
efficient 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.
34
— 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 difference 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
Please note, that scripting is an experimental feature, meaning that no compatibility guarantees on the API are given.
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 files . Scratch file is a kotlin script file with a .kts extension which you
can run and get evaluation results directly in the editor.
35
Getting Started
Basic Syntax
De ning packages
Package specification should be at the top of the source file:
package my.demo
import java.util.*
// ...
It is not required to match directories and packages: source files can be placed arbitrarily in the file system.
See Packages.
De ning functions
Function having two Int parameters with Int return type:
See Functions.
De ning variables
Assign-once (read-only) local variable:
36
val a: Int = 1 // immediate assignment
val b = 2 // `Int` type is inferred
val c: Int // Type required when no initializer is provided
c = 3 // deferred assignment
Mutable variable:
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.
var a = 1
// simple name in template:
val s1 = "a is $a"
a = 2
// arbitrary expression in template:
val s2 = "${s1.replace("is", "was")}, but now is $a"
Using if as an expression:
37
fun maxOf(a: Int, b: Int) = if (a > b) a else b
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.
38
fun getStringLength(obj: Any): Int? {
if (obj is String) {
// `obj` is automatically cast to `String` in this branch
return obj.length
}
or
or even
return null
}
or
39
Using when expression
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:
See Ranges.
Using collections
Iterating over a collection:
40
Checking if a collection contains an object using in operator:
when {
"orange" in items -> println("juicy")
"apple" in items -> println("apple is fine too")
}
41
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 -> ...
}
Using ranges
42
for (i in 1..100) { ... } // closed range: includes 100
for (i in 1 until 100) { ... } // half-open range: does not include 100
for (x in 2..10 step 2) { ... }
for (x in 10 downTo 1) { ... }
if (x in 1..10) { ... }
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)
println(files?.size ?: "empty")
43
val values = ...
val email = values["email"] ?: throw IllegalStateException("Email is missing!")
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
44
Builder-style usage of methods that return Unit
Single-expression functions
fun theAnswer() = 42
This is equivalent to
This can be effectively 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)
}
Convenient form for a generic function that requires the generic type information
45
// public final class Gson {
// ...
// public <T> T fromJson(JsonElement json, Class<T> classOfT) throws JsonSyntaxException {
// ...
46
Coding Conventions
This page contains the current coding style for the Kotlin language.
To configure 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 "Predefined 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 files should reside in the same source root as the Java source files, and follow the
same directory structure (each file 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, files with the
"org.example.kotlin" package should be placed directly under the source root, and files in "org.example.kotlin.foo.bar" should
be in the "foo/bar" subdirectory of the source root).
Source le names
If a Kotlin file 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 file contains multiple classes, or only top-level declarations, choose a name
describing what the file contains, and name the file accordingly. Use camel humps with an uppercase first letter (e.g.
ProcessDeclarations.kt ).
The name of the file should describe what the code in the file does. Therefore, you should avoid using meaningless words
such as "Util" in file names.
Source le organization
Placing multiple declarations (classes, top-level functions or properties) in the same Kotlin source file is encouraged as long as
these declarations are closely related to each other semantically and the file size remains reasonable (not exceeding a few
hundred lines).
In particular, when defining extension functions for a class which are relevant for all clients of this class, put them in the same
file where the class itself is defined. When defining extension functions that make sense only for a specific client, put them
next to the code of that client. Do not create files just to hold "all extensions of Foo".
Class layout
47
— Companion object
Do not sort the method declarations alphabetically or by visibility, and do not separate regular methods from extension
methods. Instead, put related stuff 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 stuff first, 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:
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
48
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:
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 prefix 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
first 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 vertically with the opening construct.
if (elements != null) {
for (element in elements) {
// ...
}
}
49
(Note: In Kotlin, semicolons are optional, and therefore line breaks are significant. The language design assumes Java-style
braces, and you may encounter surprising behavior if you try to use a different 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 flow 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 identifier to a name with a different length should not
affect the formatting of either the declaration or any of the usages.
Colon
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:
50
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 first and then each interface should be located in a
different 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 vertically:
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 {
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 modifiers, always put them in the following order:
51
public / protected / private / internal
expect / actual
final / open / abstract / sealed / const
external
override
lateinit
tailrec
vararg
suspend
inner
enum / annotation
companion
inline
infix
operator
data
@Named("Foo")
private val foo: Foo
Annotation formatting
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 file comment (if any), before the package statement, and are separated from package
with a blank line (to emphasize the fact that they target the file and not the package).
package foo.bar
Function formatting
If the function signature doesn't fit on a single line, use the following syntax:
52
fun longMethodName(
argument: ArgumentType = defaultValue,
argument2: AnotherArgumentType
): ReturnType {
// body
}
Prefer using an expression body for functions with the body consisting of a single expression.
If the function has an expression body that doesn't fit in the same line as the declaration, put the = sign on the first 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)
}
53
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
}
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 first 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.
54
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.
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 first line, followed by the arrow and the newline:
If the parameter list is too long to fit 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 fit into the flow of the main text.
55
// 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
modified 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:
56
// 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 defining 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.
57
return if (x) foo() else bar()
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).
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:
58
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.
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 infix 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 different 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:
59
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:
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
60
// 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)
61
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 different 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
62
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 different 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
— 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
63
val l = 1L + 3 // Long + Int => Long
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 infix form, for
example:
Here is the complete list of bitwise operations (available for Int and Long only):
— or(bits) – bitwise or
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 floating 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' .
64
fun decimalDigitValue(c: Char): Int {
if (c !in '0'..'9')
throw IllegalArgumentException("Out of range")
return c.toInt() - '0'.toInt() // Explicit conversions to numbers
}
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.
— || – 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 filled 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
65
Unsigned types are available only since Kotlin 1.3 and currently are experimental. See details below
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 suffix indicating a specific
unsigned type (similarly to Float/Long):
— suffixes 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
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
66
@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)
}
You can concatenate strings using the + operator. This also works for concatenating strings with values of other types, as
long as the first 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 prefix, but you can choose another character and pass it as a parameter, like
trimMargin(">") .
67
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"
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:
68
Packages
A source file may start with a package declaration:
package foo.bar
// ...
All the contents (such as classes and functions) of the source file 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 specified, the contents of such a file belong to "default" package that has no name.
Default Imports
A number of packages are imported into every Kotlin file 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 file may contain its own import directives. Syntax for imports is described in the grammar.
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:
69
functions and properties declared in object declarations;
—
— enum constants.
Unlike Java, Kotlin does not have a separate "import static" syntax; all of these declarations are imported using the regular
import keyword.
70
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 fine 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 satisfied. when can be used either
as an expression or as a statement. If it is used as an expression, the value of the satisfied 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.)
The else branch is evaluated if none of the other branch conditions are satisfied. 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:
71
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)
}
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:
72
for (item: Int in ints) {
// ...
}
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
while and do..while work as usual
while (x > 0) {
x--
}
do {
val y = retrieveData()
} while (y != null) // y is visible here!
73
Returns and Jumps
Kotlin has three structural jump expressions:
— return. By default returns from the nearest enclosing function or anonymous function.
A break qualified 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. Qualified 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:
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")
}
74
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 qualified return, i.e.
return@a 1
means "return 1 at label @a " and not "return a labeled expression (@a 1) ".
75
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 modifiers, the constructor keyword can be omitted:
The primary constructor cannot contain any code. Initialization code can be placed in initializer blocks, which are prefixed
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:
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:
76
class Customer(name: String) {
val customerKey = name.toUpperCase()
}
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 modifiers, the constructor keyword is required, and the modifiers go before it:
Secondary Constructors
The class can also declare secondary constructors, which are prefixed 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:
Note that code in initializer blocks effectively becomes part of the primary constructor. Delegation to the primary constructor
happens as the first 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:
77
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
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 different secondary constructors can
call different 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 annotations for
overridable members (we call them open) and for overrides:
78
open class Base {
open fun v() { ... }
fun nv() { ... }
}
class Derived() : Base() {
override fun v() { ... }
}
The override annotation is required for Derived.v() . If it were missing, the compiler would complain. If there is no open
annotation on a function, like Base.nv() , declaring a method with the same signature in a subclass is illegal, either with
override or without it. In a final class (e.g. a class with no open annotation), open members are prohibited.
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
Overriding properties works in a similar way to overriding methods; properties declared on a superclass that are then
redeclared on a derived class must be prefaced with override, and they must have a compatible type. Each declared property
can be overridden by a property with an initializer or by a property with a getter method.
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 first 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.
79
//sampleStart
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 qualified with the outer class
name: super@Outer :
Overriding Rules
80
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 qualified
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 fine 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.
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 specifically, 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 qualifier.
81
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 differs 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 write custom accessors, very much like ordinary functions, right inside a property declaration. Here's an example of a
custom getter:
By convention, the name of the setter parameter is value , but you can choose a different 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 define the accessor without defining its body:
82
var setterVisibility: String = "abc"
private set // the setter is private and has the default implementation
Backing Fields
Fields cannot be declared directly in Kotlin classes. However, when a property needs a backing field, Kotlin provides it
automatically. This backing field can be referenced in the accessors using the field identifier:
var counter = 0 // Note: the initializer assigns the backing field directly
set(value) {
if (value >= 0) field = value
}
The field identifier can only be used in the accessors of the property.
A backing field 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 identifier.
Backing Properties
If you want to do something that does not fit into this "implicit backing field" scheme, you can always fall back to having a
backing property:
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 modifier.
Such properties need to fulfil the following requirements:
— No custom getter
To handle this case, you can mark the property with the lateinit modifier:
83
public class MyTest {
lateinit var subject: TestSubject
The modifier 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 identifies 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 file.
Overriding Properties
See Overriding Properties
Delegated Properties
The most common kind of properties simply reads from (and maybe writes to) a backing field. 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.
84
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 different 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 fields, 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 define the missing
implementations:
85
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()).
86
Visibility Modi ers
Classes, objects, interfaces, constructors, functions, properties and their setters can have visibility modifiers . (Getters always
have the same visibility as the property.) There are four visibility modifiers in Kotlin: private , protected , internal and
public . The default visibility, used if there is no explicit modifier, is public .
Below please find explanations of how the modifiers apply to different 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 modifier, 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 file containing the declaration;
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.
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:
87
open class Outer {
private val a = 1
protected open val b = 2
internal val c = 3
val d = 4 // public by default
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 effectively 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 modifiers.
Modules
The internal visibility modifier means that the member is visible within the same module. More specifically, a module is a set
of Kotlin files compiled together:
— a set of files compiled with one invocation of the <kotlinc> Ant task.
88
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 prefix 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:
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 defined which has the same receiver type, the same name is
applicable to given arguments, the member always wins. For example:
89
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 different
signature:
class C {
fun foo() { println("member") }
}
Nullable Receiver
Note that extensions can be defined 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
Similarly to functions, Kotlin supports extension properties:
Note that, since extensions do not actually insert members into classes, there's no efficient way for an extension property to
have a backing field. This is why initializers are not allowed for extension properties. Their behavior can only be
defined 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 qualifier:
MyClass.foo()
Scope of Extensions
Most of the time we define extensions on the top level, i.e. directly under packages:
package foo.bar
90
To use such an extension outside its declaring package, we need to import it at the call site:
package com.example.usage
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 conflict 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 qualified this syntax.
class C {
fun D.foo() {
toString() // calls D.toString()
this@C.toString() // 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.
91
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")
}
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 file has access to the other private top-level declarations in the same file;
— 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:
// 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.
92
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 fulfill the following requirements:
Additionally, the members generation follows these rules with regard to the members inheritance:
— If there are explicit implementations of equals() , hashCode() or toString() in the data class body or final
implementations in a superclass, then these functions are not generated, and the existing implementations are used;
— If a supertype has the componentN() functions that are open and return compatible types, the corresponding functions
are generated for the data class and override those of the supertype. If the functions of the supertype cannot be
overridden due to incompatible signatures or being final, an error is reported;
— Deriving a data class from a type that already has a copy(...) function with a matching signature is deprecated in Kotlin
1.2 and will be prohibited in Kotlin 1.3.
— Providing explicit implementations for the componentN() and copy() functions is not allowed.
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
specified (see Constructors).
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 different ages, they will be
treated as equal.
93
data class Person(val name: String) {
var age: Int = 0
}
fun main(args: Array<String>) {
//sampleStart
val person1 = Person("John")
val person2 = Person("John")
person1.age = 10
person2.age = 20
//sampleEnd
println("person1 == person2: ${person1 == person2}")
println("person1 with age ${person1.age}: ${person1}")
println("person2 with age ${person2.age}: ${person2}")
}
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:
94
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 modifier before the name of the class. A sealed class can have subclasses, but
all of them must be declared in the same file 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 file.
The key benefit 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.
95
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 Effective Java, 3rd Edition, Item
31: Use bounded wildcards to increase API flexibility. 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):
// 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 Effective 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.
96
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 fine. 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 flexibility, 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 different story.
Declaration-site variance
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();
}
Then, it would be perfectly safe to store a reference to an instance of Source<String> in a variable of type Source<Object> –
there are no consumer-methods to call. But Java does not know this, and still prohibits it:
// Java
void demo(Source<String> strs) {
Source<Object> objects = strs; // !!! Not allowed in Java
// ...
}
To fix 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 modifier:
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 modifier 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.
97
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 :
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 inflexibilities. 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:
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
98
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 define 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:
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 specified 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 specified) is Any? . Only one upper bound can be specified inside the angle brackets. If the
same type parameter needs more than one upper bound, we need a separate where-clause:
99
fun <T> copyWhenGreater(list: List<T>, threshold: T): List<String>
where T : CharSequence,
T : Comparable<T> {
return list.filter { it > threshold }.map { it.toString() }
}
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<*> .
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, reified
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.
100
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 Qualified 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 prefixed with the type of the interface:
101
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 defines any members, you
need to separate the enum constant definitions from the member definitions with a semicolon, just like in Java.
Enum entries cannot contain nested types other than inner classes (deprecated in Kotlin 1.2).
102
import java.util.function.BinaryOperator
import java.util.function.IntBinaryOperator
//sampleStart
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
};
The valueOf() method throws an IllegalArgumentException if the specified name does not match any of the enum
constants defined in the class.
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
defined in the enum class.
103
Object Expressions and Declarations
Sometimes we need to create an object of a slight modification 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 specified
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.
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 final variables.)
104
fun countClicks(window: JComponent) {
var clickCount = 0
var enterCount = 0
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.
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 qualifier:
The name of the companion object can be omitted, in which case the name Companion will be used:
105
class MyClass {
companion object { }
}
val x = MyClass.Companion
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:
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 fields, if you use the
@JvmStatic annotation. See the Java interoperability section for more details.
There is one important semantic difference 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 first time;
— a companion object is initialized when the corresponding class is loaded (resolved), matching the semantics of a Java static
initializer.
106
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 wrapped type was primitive, performance hit is terrible, because primitive types
usually are heavily optimized by runtime, while their wrappers don't get any special treatment.
To solve such kind of issues, Kotlin introduces special kind of classes called inline classes , which are introduced by placing
modifier inline before the name of the class:
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 primary property of inline classes, which inspired 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 usual 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
}
Inheritance
Inline classes are allowed to inherit interfaces:
107
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 classes hierarchy. This means 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 classes instances can be represented at
runtime either as wrappers or the underlying type. This is similar to how Int can be represented either as a primitive int or
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. The rule of thumb is, inline classes are boxed whenever they
are used as another type.
interface I
fun main() {
val f = Foo(42)
// below, 'f' first is boxed (while passing 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
That inline classes are compiled to their underlying type may lead to various obscure errors, for example, unexpected platform
signature clashes:
108
To mitigate such issues, functions which use inline classes are mangled by adding some stable hashcode to the function
name. Therefore, fun compute(x: UInt) will be in fact represented as public final void compute-<hashcode>(int x) ,
which therefore solves the clash problem.
Note that - is a invalid symbol in Java, meaning that it is impossible to call functions which accept inline classes from
Java.
However, the crucial difference 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 into the usage of experimental features by passing the argument -
XXLanguage:+InlineClasses to the kotlinc .
compileKotlin {
kotlinOptions.freeCompilerArgs += ["-XXLanguage:+InlineClasses"]
}
<configuration>
<args>
<arg>-XXLanguage:+InlineClasses</arg>
</args>
</configuration>
109
Further discussion
See this language proposal for inline classes for other technical details and discussion .
110
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
specified object:
interface Base {
fun 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 print is called:
interface Base {
fun printMessage()
fun 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:
111
interface Base {
val message: String
fun print()
}
112
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 first access;
— observable properties: listeners get notified about changes to this property;
— storing properties in a map, instead of a separate field 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 first 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:
Similarly, when we assign to p , the setValue() function is called. The first two parameters are the same, and the third holds
the value being assigned:
e.p = "NEW"
This prints
The specification of the requirements to the delegated object can be found below.
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 find 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 first call to get() executes the lambda passed to lazy() and remembers the result, subsequent calls to
get() simply return the remembered result.
113
val lazyValue: String by lazy {
println("computed!")
"Hello"
}
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 modifications. 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:
import kotlin.properties.Delegates
class User {
var name: String by Delegates.observable("<no name>") {
prop, old, new ->
println("$old -> $new")
}
}
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):
114
class User(val map: Map<String, Any?>) {
val name: String by map
val age: Int by map
}
This works also for var’s properties if you use a MutableMap instead of read-only Map :
The memoizedFoo variable will be computed on the first 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);
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:
115
interface ReadOnlyProperty<in R, out T> {
operator fun getValue(thisRef: R, property: KProperty<*>): T
}
Translation Rules
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 first argument this refers to an
instance of the outer class C and this::prop is a reflection 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 defining 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 defines 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:
class MyUI {
fun <T> bindResource(id: ResourceID<T>): ResourceLoader<T> { ... }
116
The parameters of provideDelegate are the same as for getValue :
— thisRef — must be the same or a supertype of the property owner (for extension properties — the type being extended);
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):
class C {
var prop: Type by MyDelegate()
}
Note that the provideDelegate method affects only the creation of the auxiliary property and doesn't affect the code
generated for getter or setter.
117
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 defined 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 defined 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:
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:
118
fun foo(bar: Int = 0, baz: Int = 1, qux: () -> Unit) { ... }
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 = '_'
)
When a function is called with both positional and named arguments, all the positional arguments should be placed before the
first 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:
119
Single-Expression functions
When a function returns a single expression, the curly braces can be omitted and the body is specified after a = symbol:
Explicitly declaring the return type is optional when this can be inferred by the compiler:
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 flow 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 modifier:
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 (prefix 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 infix notation (omitting the dot and the parentheses for
the call). Infix functions must satisfy the following requirements:
// is the same as
1.shl(2)
120
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 infix functions always require both the receiver and the parameter to be specified. When you're calling a method on
the current receiver using the infix 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 file, 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
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])
}
121
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 specified using angle brackets before the function name:
Inline Functions
Inline functions are explained here.
Extension Functions
Extension functions are explained in their own section.
This code calculates the fixpoint 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 specified eps precision. The
resulting code is equivalent to this more traditional style:
To be eligible for the tailrec modifier, 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/finally blocks. Currently tail
recursion is only supported in the JVM backend.
122
Higher-Order Functions and Lambdas
Kotlin functions are first-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:
The following sections explain in more detail the concepts mentioned so far.
Function types
123
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 specified 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 modifier 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.
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 first
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:
124
fun main(args: Array<String>) {
//sampleStart
val repeatFun: String.(Int) -> String = { times -> this.repeat(times) }
val twoParameters: (String, Int) -> String = repeatFun // OK
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.
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 first 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
//sampleEnd
}
Inline functions
Sometimes it is beneficial to use inline functions, which provide flexible control flow, 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:
125
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 figure 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 qualified 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:
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:
126
The parameters and the return type are specified 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 specified 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 difference 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 modified:
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 qualifiers, 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() { ... }
}
127
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 modifier:
The inline modifier affects 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 off 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 modifier:
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 fields, passed around etc.
Note that if an inline function has no inlinable function parameters and no reified type parameters, the compiler will issue a
warning, since inlining such functions is very unlikely to be beneficial (you can suppress the warning if you are sure the inlining
is needed using the annotation @Suppress("NOTHING_TO_INLINE") ).
Non-local returns
In Kotlin, we can only use a normal, unqualified 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:
128
But if the function the lambda is passed to is inlined, the return can be inlined as well, so it is allowed:
//sampleStart
fun foo() {
inlined {
return // OK: the lambda is inlined
}
}
//sampleEnd
fun main(args: Array<String>) {
foo()
}
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 flow is also not
allowed in the lambdas. To indicate that, the lambda parameter needs to be marked with the crossinline modifier:
break and continue are not yet available in inlined lambdas, but we are planning to support them too.
Here, we walk up a tree and use reflection to check if a node has a certain type. It’s all fine, 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 reified type parameters , so we can write something like this:
129
We qualified the type parameter with the reified modifier, now it’s accessible inside the function, almost as if it were a
normal class. Since the function is inlined, no reflection is needed, normal operators like !is and as are working now. Also,
we can call it as mentioned above: myTree.findParentOfType<MyTreeNodeType>() .
Though reflection may not be needed in many cases, we can still use it with a reified type parameter:
Normal functions (not marked as inline) cannot have reified parameters. A type that does not have a run-time representation
(e.g. a non-reified type parameter or a fictitious type like Nothing ) cannot be used as an argument for a reified type
parameter.
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.
130
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-specific
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-specific 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 define 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 first. This code is part of a common module:
package org.jetbrains.foo
package org.jetbrains.foo
— An expected declaration in the common module and its actual counterparts always have exactly the same fully qualified
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 .
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 modifier to other declarations as
well, including top-level declarations and annotations:
131
// 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-specific 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:
132
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 configured 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 configured in the build.gradle script in the following
way:
plugins {
id 'org.jetbrains.kotlin.multiplatform' version '1.2.71'
}
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 configuration. There are presets for each of the
supported platforms.
The source sets and their dependencies are then configured as follows:
133
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 configured 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 specific 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, first, apply the kotlin-multiplatform plugin to the project by adding the
following to the build.gradle file:
plugins {
id 'org.jetbrains.kotlin.multiplatform' version '1.2.71'
}
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);
— configuring the source sets and their dependencies;
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 different, targets are built in different ways as well and have various platform-specific 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:
134
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 different
purpose (e.g. production code, tests) and incorporate different source sets. The compilations of a target may be acccessed in
the DSL, for example, to get the task names, dependency files and compilation outputs:
kotlin {
targets {
fromPreset(presets.jvm, 'jvm6') {
def mainKotlinTaskName = compilations.main.compileKotlinTaskName
def mainOutputs = compilations.main.output
def testRuntimeClasspath = compilations.test.runtimeDependencyFiles
}
}
}
All of the targets may share some of the sources and may have platform-specific sources in their compilations as well. See
Configuring source sets for details.
Some targets may require additional configuration. For Android and iOS examples, see the [Multiplatform Project: iOS and
Android] TODO /docs/tutorials/native/mpp-ios-android.html 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.
If you apply a target preset, some source sets are created and configured by default. See Default Project Layout.
The source sets are configured within a sourceSets { ... } block of the kotlin { ... } extension:
135
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.
A source set by itself is platform-agnostic, but it can be considered platform-specific if it is only compiled for a single platform. A
source set can, therefore, contain either common code shared between the platforms or platform-specific code.
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:
— 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 files 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
specified as implementation dependencies;
— foo may contain platform-specific implementations for the expected declarations of bar ;
The source sets DSL can be used to define 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-specific source sets should
depend on the custom ones, directly or indirectly:
136
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 et for target 'linux'
dependsOn desktopTest
}
/* ... */
}
}
Adding Dependencies
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 a library consumers. If any types
from a dependency are used in the public API, 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-specific artifact dependencies of the
platform-specific source sets. Usually, an artifact with a suffix -common (as in kotlin-stdlib-common ) or -metadata is
required.
137
If a multiplatform library is published in the experimental metadata publishing mode and the project is set up to consume it,
then it is enough to specify the corresponding dependency once for the common source set. Otherwise, each platform-
specific source set should be provided with a corresponding platform module of the library, in addition to the common module,
as shown above. A project('...') dependency on another multiplatform project is likewise resolved to an appropriate
target, even with experimental metadata disabled.
An alternative way to specify the dependencies is to use the Gradle built-in DSL at the top level with the configuration 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'
enableLanguageFeatures('InlineClasses')
progressiveMode = true // false by default
}
}
}
}
Language settings of a source set affect 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 enabled (there's no such requirement for bugfix features);
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-specific 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 .
138
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 first of these directories.
Running Tests
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.
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 JVM targets, use kotlin-test-junit or kotlin-test-testng for the corresponding asserter implementation and
annotations mapping.
For Kotlin/JS targets, add kotlin-test-js as a test dependency. At this point, test tasks for Kotlin/JS do not run tests by
default and should be manually configured to do so.
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 files may be added to the publication within the targets { ...
} block:
kotlin {
targets {
fromPreset(presets.jvm, 'jvm6') {
/* ... */
mavenPublication {
artifactId = 'sample-lib-jvm'
artifact(jvmJavadocJar)
}
}
}
}
139
Experimental metadata publishing mode
Gradle metadata publishing is an experimental Gradle feature which is not guaranteed to be backward-compatible.
Future Gradle versions may fail to resolve a dependency to a library published with current versions of Gradle
metadata. Library authors are recommended to use it to publish experimental versions of the library alongside with
the stable publishing mechanism until the feature is considered stable.
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-specific 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
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 differ 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:
— A published library dependency is used. If a library is published with experimental Gradle metadata, one can still replace the
single dependency with unambiguous dependencies on its separate target modules, as if it had no experimental Gradle
metadata.
— 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:
140
def testFrameworkAttribte = Attribute.of('com.example.testFramework', String)
kotlin {
targets {
fromPreset(presets.jvm, 'junit') {
attributes {
attribute(testingFrameworkAttribte, 'junit')
}
}
fromPreset(presets.jvm, 'testng') {
attributes {
attribute(testingFrameworkAttribte, 'testng')
}
}
}
}
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 different 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 file, 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 configure this feature for a
specific compilation.
A compilation can interact with several native libraries. Interoperability with each of them can be configured in the cinterops
block of the compilation:
141
// 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-specific 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'
}
142
Other
Destructuring Declarations
Sometimes it is convenient to destructure an object into a number of variables, for example:
This syntax is called a destructuring declaration. A destructuring declaration creates multiple variables at once. We have
declared two new variables: name and age , and can use them independently:
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.
Since data classes automatically declare componentN() functions, destructuring declarations work here.
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.
143
for ((key, value) in map) {
// do something with the key and the value
}
— present each of the elements as a pair by providing functions component1() and component2() .
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.
Note the difference 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 specific component separately:
144
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.
It is important to understand up front the difference between a read-only view of a mutable collection, and an actually
immutable collection. Both are easy to create, but the type system doesn't express the difference, so keeping track of that (if
it's relevant) is up to you.
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-efficient 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.
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.
145
Maps follow the same pattern. They can be easily instantiated and accessed like this:
146
Ranges
Range expressions are formed with rangeTo functions that have the operator form .. which is complemented by in and !in.
Range is defined 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 defined 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, defined 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.
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:
147
for (int i = first; i != last; i += step) {
// ...
}
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 defined 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 defined in their companion objects:
The last element of the progression is calculated to find 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 define their rangeTo operator, and the one provided by the standard library
for generic Comparable types is used instead:
downTo()
The downTo() extension function is defined for any pair of integral types, here are two examples:
reversed()
The reversed() extension functions are defined for each *Progression classes, and all of them return reversed
progressions:
step()
step() extension functions are defined for *Progression classes, all of them return progressions with modified step
values (function parameter). The step value is required to be always positive, therefore this function never changes the
direction of iteration:
148
fun IntProgression.step(step: Int): IntProgression {
if (step <= 0) throw IllegalArgumentException("Step must be positive, was: $step")
return IntProgression.fromClosedRange(first, last, if (this.step > 0) step else -step)
}
Note that the last value of the returned progression may become different from the last value of the original progression in
order to preserve the invariant (last - first) % step == 0 . Here is an example:
149
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())
}
Note that smart casts do not work when the compiler cannot guarantee that the variable cannot change between the check
and the usage. More specifically, 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 modified between the check and the usage, is not captured in a lambda that
modifies it, and is not a local delegated property;
— var properties - never (because the variable can be modified at any time by other code).
150
val x: String = y as String
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:
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 reified 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:
//sampleStart
inline fun <reified A, reified B> Pair<*, *>.asPairOf(): Pair<A, B>? {
if (first !is A || second !is B) return null
return first as A to second as B
}
Unchecked casts
151
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 .
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 different 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 reified 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.
152
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 qualifiers, it refers to the innermost enclosing scope . To refer to this in other scopes, label qualifiers 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:
153
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.
154
Operator overloading
Kotlin allows us to provide implementations for a predefined set of operators on our types. These operators have fixed
symbolic representation (like + or * ) and fixed precedence. To implement an operator, we provide a member function or an
extension function with a fixed 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 modifier.
Further we describe the conventions that regulate operator overloading for different operators.
Unary operations
Expression Translated to
+a a.unaryPlus()
-a a.unaryMinus()
!a a.not()
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 modifier 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:
Expression Translated to
a++ a.inc() + see below
a-- a.dec() + see below
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 postfix form, e.g. a++ :
— Looks up a function inc() with the operator modifier and no parameters, applicable to the receiver of type T ;
155
— Assign the result of a.inc() to a ;
For the prefix forms ++a and --a resolution works the same way, and the effect 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
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.
Expression Translated to
a[i] a.get(i)
a[i, j] a.get(i, j)
a[i_1, ..., i_n] a.get(i_1, ..., i_n)
a[i] = b a.set(i, b)
a[i, j] = b a.set(i, j, b)
a[i_1, ..., i_n] = b a.set(i_1, ..., i_n, b)
Square brackets are translated to calls to get and set with appropriate numbers of arguments.
156
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)
For the assignment operations, e.g. a += b , the compiler performs the following steps:
— Make sure its return type is Unit , and report an error otherwise,
— 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 ).
Expression Translated to
a == b a?.equals(b) ?: (b === null)
a != b !(a?.equals(b) ?: (b === null))
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 .
provideDelegate , getValue and setValue operator functions are described in Delegated properties.
157
In x calls for named functions
We can simulate custom infix operations by using infix function calls.
158
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:
— A superclass constructor calls an open member whose implementation in the derived class uses uninitialized state;
— 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;
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
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:
159
fun main(args: Array<String>) {
//sampleStart
val b = "Kotlin"
if (b != null && b.length > 0) {
print("String of length ${b.length}")
} else {
print("Empty string")
}
//sampleEnd
}
Note that this only works where b is immutable (i.e. a local variable which is not modified between the check and the usage or
a member val which has a backing field 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 ?. :
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:
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.
160
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
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:
161
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 affect 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:
try {
log.append(message)
}
catch (IOException e) {
// Must be safe
}
And this is no good, see Effective Java, 3rd Edition, Item 77: Don't ignore exceptions .
Examination of small programs leads to the conclusion that requiring exception specifications could both enhance
developer productivity and enhance code quality, but experience with large software projects suggests a different result
– decreased productivity and little or no increase in code quality.
162
Other citations of this sort:
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 specific type, the compiler will infer the Nothing? type:
Java Interoperability
Please see the section on exceptions in the Java Interoperability section for information about Java interoperability.
163
Annotations
Annotation Declaration
Annotations are means of attaching metadata to code. To declare an annotation, put the annotation modifier in front of a
class:
Additional attributes of the annotation can be specified by annotating the annotation class with meta-annotations:
— @Target specifies the possible kinds of elements which can be annotated with the annotation (classes, functions,
properties, expressions etc.);
— @Retention specifies whether the annotation is stored in the compiled class files and whether it's visible through
reflection at runtime (by default, both are true);
— @Repeatable allows using the same annotation on a single element multiple times;
— @MustBeDocumented specifies 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
— enums;
— other annotations;
— arrays of the types listed above.
164
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 prefixed 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.
The same syntax can be used to annotate the entire file. To do this, put an annotation with the target file at the top level of
a file, before the package directive or before all imports if the file 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 ;
165
— param (constructor parameter);
— delegate (the field 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 first applicable target from the following list is used:
— param ;
— property ;
— 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 defined, 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 specified 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();
}
166
// 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
}
167
Re ection
Reflection 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 first-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 reflection 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
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> .
168
:: 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 specified
type:
If we need to use a member of a class, or an extension function, it needs to be qualified, 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:
fun <A, B, C> compose(f: (B) -> C, g: (A) -> B): (A) -> C {
return { x -> f(g(x)) }
}
println(strings.filter(oddLength))
//sampleEnd
}
Property References
To access properties as first-class objects in Kotlin, we can also use the :: operator:
val x = 1
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:
169
var y = 1
A property reference can be used where a function with one parameter is expected:
On the Java platform, standard library contains extensions for reflection classes that provide a mapping to and from Java
reflection objects (see package kotlin.reflect.jvm ). For example, to find a backing field or a Java method that serves as a
getter for a Kotlin property, you can say something like this:
import kotlin.reflect.jvm.*
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:
170
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:
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.
A bound callable reference to a constructor of an inner class can be obtained by providing an instance of the outer class:
class Outer {
inner class Inner
}
val o = Outer()
val boundInnerCtor = o::Inner
171
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-specific languages (DSLs) suitable for building complex hierarchical data
structures in a semi-declarative way. Some of the example use cases for the builders are:
// mixed content
p {
+"This is some"
b {+"mixed"}
+"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 define 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 defines 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 defined as follows:
172
fun html(init: HTML.() -> Unit): HTML {
val html = HTML()
html.init()
return html
}
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:
html {
head { ... }
body { ... }
}
So, what does this call do? Let's look at the body of html function as defined 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 defined similarly to html . The only difference 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:
173
html {
head {
title {+"XML encoding with Kotlin"}
}
// ...
}
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
prefix unaryPlus() operation. That operation is actually defined by an extension function unaryPlus() that is a member of
the TagWithText abstract class (a parent of Title ):
So, what the prefix + 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 defined 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 definition 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) { ... }
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
}
// ...
}
174
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 {
this@html.head { } // 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>()
175
operator fun String.unaryPlus() {
children.add(TextElement(this))
}
}
class A : BodyTag("a") {
var href: String
get() = attributes["href"]!!
set(value) {
attributes["href"] = value
}
}
176
Type aliases
Type aliases provide alternative names for existing types. If the type name is too long you can introduce a different 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:
177
Reference
Keywords and Operators
Hard Keywords
The following tokens are always interpreted as keywords and cannot be used as identifiers:
— as
— else defines 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 defines
the 'contains' method
— is used in when expressions for the same purpose
— is
— !is
— null is a constant representing an object reference that doesn't point to any object
178
—
— return returns from the nearest enclosing function or anonymous function
— super
— this
Soft Keywords
The following tokens act as keywords in the context when they are applicable and can be used as identifiers in other contexts:
— by
— finally begins a block that is always executed when a try block exits
— get
— import imports a declaration from another package into the current file
— set
Modi er Keywords
The following tokens act as keywords in modifier lists of declarations and can be used as identifiers in other contexts:
179
— actual denotes a platform-specific implementation in multiplatform projects
— external marks a declaration as implemented not in Kotlin (accessible through JNI or in JavaScript)
— 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)
— field is used inside a property accessor to refer to the backing field of the property
— + , - , * , / , % - mathematical operators
— =
— assignment operator
— is used to specify default values for parameters
180
— ++ , -- - increment and decrement operators
— && , || , ! - logical 'and', 'or', 'not' operators (for bitwise operations, use corresponding infix functions)
— < , > , <= , >= - comparison operators (translated to calls of compareTo() for non-primitive types)
— ?. 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
— _
181
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
(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)
182
: 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
(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)
183
: 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)
: 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
enumClassBody
(used by class)
: "{" enumEntries (";" members)? "}"
;
enumEntries
(used by enumClassBody)
: (enumEntry{","} ","? ";"?)?
;
enumEntry
(used by enumEntries)
: modifiers SimpleName valueArguments? classBody?
;
184
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)
: 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
185
Precedence
Rules
expression
(used by for, atomicExpression, longTemplate, whenCondition, functionBody, doWhile, property, script, explicitDelegation,
jump, while, arrayAccess, blockLevelExpression, if, when, valueArguments, functionParameter)
: 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
186
(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)
: 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?" : ":"
187
;
isOperation
(used by namedInfix)
: "is" : "!is"
;
comparisonOperation
(used by comparison)
: "<" : ">" : ">=" : "<="
;
equalityOperation
(used by equalityComparison)
: "!=" : "=="
;
assignmentOperator
(used by expression)
: "="
: "+=" : "-=" : "*=" : "/=" : "%="
;
prefixUnaryOperation
(used by prefixUnaryExpression)
: "-" : "+"
: "++" : "--"
: "!"
: 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)
188
: "[" element{","}? "]"
;
When-expression
See When-expression
when
(used by atomicExpression)
: "when" ("(" expression ")")? "{"
whenEntry*
"}"
;
whenEntry
(used by when)
: 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
;
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"
189
;
functionModifier
(used by modifier)
: "tailrec"
: "operator"
: "infix"
: "inline"
: "external"
: suspendModifier
;
propertyModifier
(used by modifier)
: "const"
;
suspendModifier
(used by typeModifiers, functionModifier)
: "suspend"
;
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
: "0" ("x" | "X") HexDigit (HexDigit | "_")* HexDigit
;
helper
190
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
191
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()
}
}
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.
192
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):
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:
— (Mutable)Collection<T>! means "Java collection of T may be mutable or not, may be nullable or not",
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 flavors of nullability annotations, including:
— FindBugs ( edu.umd.cs.findbugs.annotations )
— Eclipse ( org.eclipse.jdt.annotation )
— Lombok ( lombok.NonNull ).
You can find 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) { ... }
193
It leads to the following signature seen in Kotlin:
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).
JSR-305 Support
The @Nonnull annotation defined 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 qualifiers (KEEP-79) are also supported (see below).
If an annotation type is annotated with both @TypeQualifierNickname and JSR-305 @Nonnull (or its another nickname, such
as @CheckForNull ), then the annotation type is itself used for retrieving precise nullability and has the same meaning as that
nullability annotation:
@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?`
@TypeQualifierDefault allows introducing annotations that, when being applied, define the default nullability within the scope
of the annotated element.
Such annotation type should itself be annotated with both @Nonnull (or its nickname) and @TypeQualifierDefault(...)
with one or more ElementType values:
194
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 qualifier default annotation with the ElementType matching the type
usage.
@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 configuration sections.
// FILE: test/package-info.java
@NonNullApi // declaring all types in package 'test' as non-nullable by default
package test;
The @UnderMigration annotation (provided in a separate artifact kotlin-annotations-jvm ) can be used by library
maintainers to define the migration status for the nullability type qualifiers.
The status value in @UnderMigration(status = ...) specifies how the compiler treats inappropriate usages of the
annotated types in Kotlin (e.g. using a @MyNullable -annotated type value as non-null):
— MigrationStatus.STRICT makes annotation work as any plain nullability annotation, i.e. report errors for the inappropriate
usages and affect the types in the annotated declarations as they are seen in Kotlin;
— with MigrationStatus.WARN , the inappropriate usages are reported as compilation warnings instead of errors, but the
types in the annotated declarations remain platform; and
A library maintainer can add @UnderMigration status to both type qualifier nicknames and type qualifier defaults:
195
@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 qualifier nicknames but is applied to its usages
in default type qualifiers.
If a default type qualifier uses a type qualifier nickname and they are both @UnderMigration , the status from the default type
qualifier is used.
The JSR-305 checks can be configured by adding the -Xjsr305 compiler flag with the following options (and their
combination):
— -Xjsr305={strict|warn|ignore} to set up the behavior for non- @UnderMigration annotations. Custom nullability
qualifiers, especially @TypeQualifierDefault , are already 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 flag only
affects non- @UnderMigration annotations.
— -Xjsr305=@<fq.name>:{strict|warn|ignore} (since 1.1.60) to override the behavior for a single annotation, where
<fq.name> is the fully qualified class name of the annotation. May appear several times for different annotations. This is
useful for managing the migration state for a particular library.
The strict , warn and ignore values have the same meaning as those of MigrationStatus , and only the strict mode
affects the types in the annotated declarations as they are seen in Kotlin.
Note: the built-in JSR-305 annotations @Nonnull, @Nullable and @CheckForNull are always enabled and affect the types
of the annotated declarations in Kotlin, regardless of compiler configuration with the -Xjsr305 flag.
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):
196
Java type
double Kotlin type
kotlin.Double
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 type Kotlin mutable type Loaded platform 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>!
197
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 qualified names of the Java types, e.g. java.lang.Integer.toHexString(foo) .
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:
198
if (i in array.indices) { // same as (i >= 0 && i < array.size)
print(array[i])
}
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 infix 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
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-specific, 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:
199
clone()
Do not forget about Effective 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
}
}
if (Character.isLetter(a)) { ... }
To access static members of a Java type that is mapped to a Kotlin type, use the full qualified name of the Java type:
java.lang.Integer.bitCount(foo) .
Java Re ection
Java reflection 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 reflection through java.lang.Class .
Other supported cases include acquiring a Java getter/setter method or a backing field for a Kotlin property, a KProperty for a
Java field, 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 specific SAM type. Those adapter functions are also generated by the compiler
when needed:
200
Note that SAM conversions only work for interfaces, not for abstract classes, even if those also have just a single abstract
method.
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.
201
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 prefix;
— A setter method, with the name calculated by prepending the set prefix (only for var properties);
— A private field, with the same name as the property name (only for properties with backing fields).
For example, var firstName: String gets compiled to the following Java declarations:
If the name of the property starts with is , a different 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 file 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:
@file:JvmName("DemoUtils")
package demo
class Foo
// Java
new demo.Foo();
demo.DemoUtils.bar();
Having multiple files 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 specified name and contains all the declarations from all the files which have that name. To enable the generation of
such a facade, use the @JvmMultifileClass annotation in all of the files.
202
// 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 field in Java, you need to annotate it with the @JvmField annotation. The field will
have the same visibility as the underlying property. You can annotate a property with @JvmField if it has a backing field, is not
private, does not have open , override or const modifiers, and is not a delegated property.
// Java
class JavaClient {
public String getID(C c) {
return c.ID;
}
}
Late-Initialized properties are also exposed as fields. The visibility of the field 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 fields either in that named object or
in the class containing the companion object.
Usually these fields are private but they can be exposed in one of the following ways:
— @JvmField annotation;
— lateinit modifier;
— const modifier.
Annotating such a property with @JvmField makes it a static field 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 field with the same visibility as the property
setter.
203
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 fields in Java:
// 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 defined 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:
@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.
204
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 defined 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 different 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 .
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
defined in interfaces.
205
class Foo @JvmOverloads constructor(x: Int, y: Double = 0.0) {
@JvmOverloads fun f(a: String, b: Int = 0, c: String = "abc") { ... }
}
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 specified.
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:
// 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:
206
class Box<out T>(val value: T)
interface Base
class Derived : Base
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 define 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 defined Box (or Foo<?
super Bar> for contravariantly defined 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 final, 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:
207
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;
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-defined 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
}
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
— prefix: - , + , !
— assignments: += , -= , *= , /= , %=
— indexed access:
— read: d[a] , more than one argument is an error
208
in , !in and .. operations with values of type dynamic are forbidden.
209
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 modifier. 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 modifier is inherited by nested declarations, i.e. in Node class we do not put external before member
functions and properties.
The external modifier is only allowed on package-level declarations. You can't declare an external member of a
non- external class.
In JavaScript you can define 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:
210
external class MyClass {
companion object {
fun sharedMember()
}
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 define 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.
2. You can't override a function with default arguments.
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:
211
external interface JQueryAjaxSettings {
var async: Boolean
// etc
}
fun sendQuery() {
JQuery.get(JQueryAjaxSettings().apply {
complete = { (xhr, data) ->
window.alert("Request complete")
}
})
}
212
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 define your declarations in the root package, you have to use
fully-qualified 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:
// 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 suffix 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 identifier. The compiler will report an error
on any attempt to pass non-identifier string to @JsName . The following example produces a compile-time error:
213
@JsName("new C()") // error here
external fun newC()
— 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)
}
— Kotlin preserves overflow semantics for kotlin.Int , kotlin.Byte , kotlin.Short , kotlin.Char and kotlin.Long .
— There's no 64 bit integer number in JavaScript, so kotlin.Long is not mapped to any JavaScript object, it's emulated by a
Kotlin class.
— kotlin.String is mapped to JavaScript String.
— Kotlin collections (i.e. List , Set , Map , etc) are not mapped to any specific JavaScript type.
Starting with version 1.1.50 primitive array translation utilizes JavaScript TypedArray:
214
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.
2. Asynchronous Module Definition (AMD), which is in particular used by require.js library.
3. CommonJS convention, widely used by node.js/npm ( require function and module.exports object)
4. Unified Module Definitions (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…, find your module in Modules and select "Kotlin" facet under it. Choose
appropriate module system in "Module kind" field.
Setup for the whole project: Open File -> Settings, select "Build, Execution, Deployment" -> "Compiler" -> "Kotlin compiler".
Choose appropriate module system in "Module kind" field.
From Maven
To select module system when compiling via Maven, you should set moduleKind configuration 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
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":
215
module.exports.sayHello = function(name) { alert("Hello, " + name); }
@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: files 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
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 file 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 files:
@file:JsModule("extModule")
@file:JsQualifier("mylib.pkg1")
package extlib.pkg1
and
216
@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 files 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:
@JsModule("hello")
@JsNonModule
@JsName("topLevelSayHello")
external fun sayHello(name: String)
Notes
Kotlin is distributed with kotlin.js standard library as a single file, 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
217
JavaScript Re ection
At this time, JavaScript does not support the full Kotlin reflection 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"
218
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 file. A simple "Hello, world" application only requires console routines, which is only few kilobytes for the
entire file.
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 files (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 configure 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 :
moduleName.dot.separated.package.name.declarationName
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"
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 flag 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.
219
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 configuration 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 minification (uglification) of your code by removing unnecessary whitespaces and shortening
identifiers. 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.
220
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 offers the concept of workers: concurrently executed control flow 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.
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 first 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.
221
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.
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.
An object subgraph without external references can be disconnected using DetachedObjectGraph<T> to a COpaquePointer
value, which could be stored in void* data, so the disconnected object subgraphs can be stored in a C data structure, and
later attached back with DetachedObjectGraph<T>.attach() in an arbitrary thread or a worker. Combining it with raw memory
sharing it allows side channel object transfer between concurrent threads, if the worker mechanisms are insufficient for a
particular task.
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
file:
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 different threads
and building traditional concurrent structures with platform-specific synchronization primitives.
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 first 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
222
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.
223
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 ).
Immutability is a runtime property in Kotlin/Native, and can be applied to an arbitrary object subgraph using the
kotlin.native.concurrent.freeze function. It makes all the objects reachable from the given one immutable, such a
transition is a one-way operation (i.e., objects cannot be unfrozen later). Some naturally immutable objects such as
kotlin.String , kotlin.Int , and other primitive types, along with AtomicInt and AtomicReference are frozen by default. If
a mutating operation is applied to a frozen object, an InvalidMutabilityException is thrown.
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 first) 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.
224
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> flag. 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.
All of the above commands accept an additional -repository <directory> argument for specifying a repository different 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
225
Now let's check out the contents of the library:
$ 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
* 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.
226
An example layout can be found in klib/stdlib directory of your installation.
227
Platform libraries
Overview
To provide access to user's native operating system services, Kotlin/Native distribution includes a set of prebuilt libraries
specific 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 different platforms, in the same way as different POSIX
implementations are a little different.
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 flags need to be specified 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.
228
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 workflow 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.
Interoperability with Swift/Objective-C is provided too and covered in a separate document OBJC_INTEROP.md.
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 ../..
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 modified, you can use a format like compilerOpts.osx or
compilerOpts.linux to provide platform-specific values to the options.
Note, that the generated bindings are generally platform-specific, 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.
229
For a typical Unix library with a config script, the compilerOpts will likely contain the output of a config script with the --
cflags flag (maybe without exact paths).
The output of a config script with --libs will be passed as a -linkedArgs kotlinc flag 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 file 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 filter headers by globs. The headerFilter property value from the .def file 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 filter headers with
headerFilter = SomeLibrary/**
Some libraries have proper module.modulemap or module.map files in its headers. For example, macOS and iOS system
libraries and frameworks do. The module map file describes the correspondence between header files and modules. When
the module maps are available, the headers from the modules that are not included directly can be filtered out using the
experimental excludeDependentModules option of the .def file:
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 definitions) and the linker (used to link final
executables) can be passed in the definition file as compilerOpts and linkerOpts respectively. For example
compilerOpts = -DFOO=bar
linkerOpts = -lpng
Target-specific options, only applicable to the certain target can be specified 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 definition file option can have both common and the platform-specific 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 file with these declarations, you can include them directly to the end of the .def file, after a
separating line, containing only the separator sequence --- :
230
headers = errno.h
---
Note that this part of the .def file is treated as part of the header file, so functions with the body should be declared as
static . The declarations are parsed after including the files 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 floating 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 definition file hints.
— Structs are mapped to types having fields available via the dot notation, i.e. someStructInstance.field1 .
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
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.
231
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.
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 define 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.
The CValuesRef<T> representation of pointer parameters is designed to support C array literals without explicit native memory
allocation. To construct the immutable self-contained sequence of C values, the following methods are provided:
— Array<CPointer<T>?>.toCValues() , List<CPointer<T>?>.toCValues()
For example:
C:
232
void foo(int* elements, int count);
...
int elements[] = {1, 2, 3};
foo(elements, 3);
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 file 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
It is possible to create a scope-stable pointer of C representation of CValues<T> instance using the CValues<T>.ptr
extension property, available under memScoped { ... } . It allows using the APIs which require C pointers with a lifetime bound
to a certain MemScope . For example:
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 flow leaves the memScoped scope the C pointers become invalid.
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 fields cannot be accessed with the appropriate Kotlin properties. It should be
possible, if an API uses structures as handles, but if field access is required, there are the following conversion methods
available:
— fun T.readValue(): CValue<T> . Converts (the lvalue) T to a CValue<T> . So to construct the CValue<T> , T can be
allocated, filled, and then converted to CValue<T> .
233
— CValue<T>.useContents(block: T.() -> R): R . Temporarily places the CValue<T> to memory, and then runs the
passed lambda with this placed value T as receiver. So to read a single field, the following code can be used:
Callbacks
To convert a Kotlin function to a pointer to a C function, staticCFunction(::kotlinFunction) can be used. It is also able to
provide the lambda instead of a function reference. The function or lambda must not capture any values.
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 configuring 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 configuring 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.
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 file supports several options for adjusting the generated bindings.
— excludedFunctions property value specifies a space-separated list of the names of functions that should be ignored.
This may be required because a function declared in the C header is not generally guaranteed to be really callable, and it is
often hard or impossible to figure this out automatically. This option can also be used to workaround a bug in the interop
itself.
234
— strictEnums and nonStrictEnums properties values are space-separated lists of the enums that should be generated
as a Kotlin enum or as integral values correspondingly. If the enum is not included into any of these lists, then it is
generated according to the heuristics.
— noStringConversion property value is space-separated lists of the functions whose const char* parameters shall not
be autoconverted as Kotlin string
Portability
Sometimes the C libraries have function parameters or struct fields 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:
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.
235
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 suffix, i.e. @protocol Foo -> interface FooProtocol . These classes and interfaces are placed into a package
specified in build configuration ( platform.* packages for preconfigured system frameworks).
The names of Kotlin classes and interfaces are prefixed when imported to Objective-C. The prefix 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.
236
Top-level functions and properties
Top-level Kotlin functions and properties are accessible as members of special classes. Each Kotlin file 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 different 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 .
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 prefix).
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
NSMutableString Objective-C class is not available from Kotlin. All instances of NSMutableString are copied when passed to
Kotlin.
237
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 prefix). The same holds for MutableMap .
Function types
Kotlin function-typed objects (e.g. lambdas) are converted to Swift functions / Objective-C blocks. However there is a difference
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.
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.
238
To override different 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 file 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.).
239
Kotlin/Native Gradle plugin
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 first 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
Source management in the kotlin.platform.native plugin is uniform with other Kotlin plugins and is based on source sets.
A source set is a group of Kotlin/Native source which may contain both common and platform-specific code. The plugin
provides a top-level script block sourceSets allowing you to configure source sets. Also it creates the default source sets
main and test (for production and test code respectively).
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
240
Components allow you to specify:
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 specified 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 configuration script block. The plugin supports producing binaries of
the following kinds:
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 final binary (executable, static lib etc) and affect 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 specified 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
241
Dependencies
The plugin allows you to declare dependencies on files and other projects using traditional Gradle's mechanism of
configurations. 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')
Now you can declare a dependency on a Kotlin/Native library in the traditional group:artifact:version notation:
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
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-specific 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'
}
}
242
Also the allTargets block is available.
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:
components.main {
pom {
withXml {
def root = asNode()
root.appendNode('name', 'My library')
root.appendNode('description', 'A Kotlin/Native library')
}
}
}
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'
}
243
// Targets independent options
allTargets {
linkerOpts '-L/common/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")
// Directories for header search (an analogue of the -I<path> compiler option).
allHeaders 'path1', 'path2'
244
Debugging
Currently the Kotlin/Native compiler produces debug info compatible with the DWARF 2 specification, 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 sufficient to use the -g option on the command line.
Example:
Breakpoints
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
245
(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 find 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
(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 :
246
λ 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 }
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):
247
0:b-debugger-fixes:minamoto@unit-703(0)# cat ../debugger-plugin/1.kt | nl -p
1 fun foo(a:String, b:Int) = a + b
2 fun one() = 1
3 fun main(arg:Array<String>) {
4 var a_variable = foo("(a_variable) one is ", 1)
5 var b_variable = foo("(b_variable) two is ", 2)
6 var c_variable = foo("(c_variable) two is ", 3)
7 var d_variable = foo("(d_variable) two is ", 4)
8 println(a_variable)
9 println(b_variable)
10 println(c_variable)
11 println(d_variable)
12 }
0:b-debugger-fixes:minamoto@unit-703(0)# lldb ./program.kexe -o 'b -f 1.kt -l 9' -o r
(lldb) target create "./program.kexe"
Current executable set to './program.kexe' (x86_64).
(lldb) b -f 1.kt -l 9
Breakpoint 1: where = program.kexe`kfun:main(kotlin.Array<kotlin.String>) + 463 at 1.kt:9, address =
0x0000000100000dbf
(lldb) r
(a_variable) one is 1
Process 80496 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100000dbf program.kexe`kfun:main(kotlin.Array<kotlin.String>) at 1.kt:9
6 var c_variable = foo("(c_variable) two is ", 3)
7 var d_variable = foo("(d_variable) two is ", 4)
8 println(a_variable)
-> 9 println(b_variable)
10 println(c_variable)
11 println(d_variable)
12 }
Known issues
Note: Supporting the DWARF 2 specification means that the debugger tool recognizes Kotlin as C89, because before the
DWARF 5 specification, there is no identifier for the Kotlin language type in specification.
248
Q: How do I run my program?
A: Define 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.
A: Use the -produce dynamic compiler switch, or konanArtifacts { dynamic('foo') {} } in Gradle. It will produce a
platform-specific 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.
A: Use the -produce static compiler switch, or konanArtifacts { static('foo') {} } in Gradle. It will produce a
platform-specific 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.
A: As Kotlin/Native needs to download a platform specific 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.
framework("MyCustomFramework") {
extraOpts '-module_name', 'TheName'
}
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 different
pointers to frozen objects in a frozen object and automatically update them.
A: We release dev builds frequently, usually at least once a week. You can check the list of available versions. But if we recently
fixed 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:
249
Coroutines
Table of contents
— Coroutine basics
— Your first 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.
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.
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.
250
Bridging blocking and non-blocking worlds
The first example mixes non-blocking delay(...) and blocking Thread.sleep(...) in the same code. It is easy to get lost
which one is blocking and which one is not. Let's be explicit about blocking using runBlocking coroutine builder:
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:
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 .
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:
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.
251
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 specific 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 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:
Scope builder
In addition to the coroutine scope provided by different 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
difference between runBlocking and coroutineScope is that the latter does not block the current thread while waiting for all
children to complete.
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 modifier. That is your first 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.
252
fun main(args: Array<String>) = runBlocking {
launch { doWorld() }
println("Hello,")
}
But what if the extracted function contains a coroutine builder which is invoked on the current scope? In this case suspend
modifier 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 field 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.
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:
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.
253
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 for asynchronous operations than futures and promises.
kotlinx.coroutines is a rich library for coroutines developed by JetBrains. It contains a number of high-level coroutine-
enabled primitives that this guide covers, including launch , async and others.
This is a guide on core features of kotlinx.coroutines with a series of examples, divided up into different topics.
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
254
Table of contents
— Cancellation and timeouts
— Cancelling coroutine execution
— Cancellation is cooperative
— Making computation code cancellable
— Closing resources with finally
— Run non-cancellable block
— Timeout
In a long-running application you might need fine-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
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:
255
fun main(args: Array<String>) = runBlocking {
val startTime = System.currentTimeMillis()
val job = launch(Dispatchers.Default) {
var nextPrintTime = startTime
var i = 0
while (i < 5) { // computation loop, just wastes CPU
// print a message twice a second
if (System.currentTimeMillis() >= nextPrintTime) {
println("I'm sleeping ${i++} ...")
nextPrintTime += 500L
}
}
}
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.")
}
Run it to see that it continues to print "I'm sleeping" even after cancellation until the job completes by itself after five iterations.
There are two approaches to making computation code cancellable. The first 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 later approach.
Replace while (i < 5) in the previous example with while (isActive) and rerun it.
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.
Cancellable suspending functions throw CancellationException on cancellation which can be handled in a usual way. For
example, try {...} finally {...} expression and Kotlin use function execute their finalization actions normally when
coroutine is cancelled:
256
fun main(args: Array<String>) = runBlocking {
val job = launch {
try {
repeat(1000) { i ->
println("I'm sleeping $i ...")
delay(500L)
}
} finally {
println("I'm running finally")
}
}
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.")
}
Both join and cancelAndJoin wait for all the finalization 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 file, 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:
Timeout
257
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:
The TimeoutCancellationException that is thrown by withTimeout is a subclass of CancellationException. We have not seen
its stack trace printed on the console before. That is because inside a cancelled coroutine CancellationException is
considered to be a normal reason for coroutine completion. However, in this example we have used withTimeout right inside
the main function.
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 specifically on
any kind of timeout or use withTimeoutOrNull function that is similar to withTimeout, but returns null on timeout instead of
throwing an exception:
258
Table of contents
— Channels (experimental)
— Channel basics
— Closing and iteration over channels
— Building channel producers
— Pipelines
— Prime numbers with pipeline
— Fan-out
— Fan-in
— Buffered 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.
Channels are an experimental feature of kotlinx.coroutines. Their API is expected to evolve in the upcoming updates of
the kotlinx.coroutines library with potentially breaking changes.
Channel basics
A Channel is conceptually very similar to BlockingQueue . One key difference 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.
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:
259
fun main(args: Array<String>) = runBlocking {
val channel = Channel<Int>()
launch {
for (x in 1..5) channel.send(x * x)
channel.close() // we're done sending
}
// here we print received values using `for` loop (until the channel is closed)
for (y in channel) println(y)
println("Done!")
}
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 convenience 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 infinite, stream of values:
And another coroutine or coroutines are consuming that stream, doing some processing, and producing some other results.
In the below example the numbers are just squared:
All functions that create coroutines are defined 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.
260
Prime numbers with pipeline
Let's take pipelines to the extreme with an example that generates prime numbers using a pipeline of coroutines. We start with
an infinite sequence of numbers.
The following pipeline stage filters 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) ...
The following example prints the first 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 first 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 benefit 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.
Anyway, this is an extremely impractical way to find prime numbers. In practice, pipelines do involve some other suspending
invocations (like asynchronous calls to remote services) and these pipelines cannot be built using
buildSequence / buildIterator , because they do not allow arbitrary suspension, unlike produce , which is fully
asynchronous.
Fan-out
261
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):
Then we can have several processor coroutines. In this example, they just print their id and received number:
Now let us launch five 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 specific integer may be different:
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
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 specified string to this channel with a specified 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):
262
fun main(args: Array<String>) = runBlocking {
val channel = Channel<String>()
launch { sendString(channel, "foo", 200L) }
launch { sendString(channel, "BAR!", 500L) }
repeat(6) { // receive first six
println(channel.receive())
}
coroutineContext.cancelChildren() // cancel all children to let main finish
}
foo
foo
BAR!
foo
foo
BAR!
Bu ered channels
The channels shown so far had no buffer. Unbuffered channels transfer elements when sender and receiver meet each other
(aka rendezvous). If send is invoked first, then it is suspended until receive is invoked, if receive is invoked first, it is
suspended until send is invoked.
Both Channel() factory function and produce builder take an optional capacity parameter to specify buffer size . Buffer allows
senders to send multiple elements before suspending, similar to the BlockingQueue with a specified capacity, which blocks
when buffer is full.
It prints "sending" five times using a buffered channel with capacity of four:
Sending 0
Sending 1
Sending 2
Sending 3
Sending 4
The first four elements are added to the buffer and the sender suspends when trying to send the fifth one.
263
Send and receive operations to channels are fair with respect to the order of their invocation from multiple coroutines. They
are served in first-in first-out order, e.g. the first 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.
The "ping" coroutine is started first, so it is the first 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.
264
fun main(args: Array<String>) = runBlocking<Unit> {
val tickerChannel = ticker(delayMillis = 100, initialDelayMillis = 0) // create ticker channel
var nextElement = withTimeoutOrNull(1) { tickerChannel.receive() }
println("Initial element is available immediately: $nextElement") // initial delay hasn't passed yet
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 fixed rate of produced elements.
Optionally, a mode parameter equal to TickerMode.FIXED_DELAY can be specified to maintain a fixed delay between elements.
265
Table of contents
— Composing suspending functions
— Sequential by default
— Concurrent using async
— Lazily started async
— Async-style functions
— Structured concurrency with async
Sequential by default
Assume that we have two suspending functions defined 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:
What do we do if need to invoke them sequentially – first doSomethingUsefulOne and then doSomethingUsefulTwo and
compute the sum of their results? In practice we do this if we use the results of the first function to make a decision on
whether we need to invoke the second one or to decide on how to invoke it.
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:
The answer is 42
Completed in 2017 ms
What if there are no dependencies between invocation of doSomethingUsefulOne and doSomethingUsefulTwo and we want
to get the answer faster, by doing both concurrently? This is where async comes to help.
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 difference 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.
266
fun main(args: Array<String>) = runBlocking<Unit> {
val time = measureTimeMillis {
val one = async { doSomethingUsefulOne() }
val two = async { doSomethingUsefulTwo() }
println("The answer is ${one.await() + two.await()}")
}
println("Completed in $time ms")
}
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:
The answer is 42
Completed in 1017 ms
So, here the two coroutines are defined 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 first start one , then start two , and then await for the
individual coroutines to finish.
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 finish, 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
We can define async-style functions that invoke doSomethingUsefulOne and doSomethingUsefulTwo asynchronously using
async coroutine builder with an explicit GlobalScope reference. We name such functions with "Async" suffix to highlight the fact
that they only start asynchronous computation and one needs to use the resulting deferred value to get the result.
267
// The result type of somethingUsefulOneAsync is Deferred<Int>
fun somethingUsefulOneAsync() = GlobalScope.async {
doSomethingUsefulOne()
}
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.
// note, that we don't have `runBlocking` to the right of `main` in this example
fun main(args: Array<String>) {
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.
Consider what happens if between val one = somethingUsefulOneAsync() line and one.await() expression there is some
logic error in the code and the program throws an exception and the operation that was being performed by the program
aborts. Normally, a global error-handler could catch this exception, log and report the error for developers, but the program
could otherwise continue doing other operations. But here we have somethingUsefulOneAsync still running in background,
despite the fact, that operation that had initiated it aborts. This problem does not happen with structured concurrency, as
shown in the section 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 defined 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.
268
You can get full code here
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
Note, how both first async and awaiting parent are cancelled on the one child failure:
269
Table of contents
— Coroutine context and dispatchers
— Dispatchers and threads
— Unconfined vs confined dispatcher
— Debugging coroutines and threads
— Jumping between threads
— Job in the context
— Children of a coroutine
— Parental responsibilities
— Naming coroutines for debugging
— Combining context elements
— Cancellation via explicit job
— Thread-local data
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 confine coroutine execution to a specific thread,
dispatch it to a thread pool, or let it run unconfined.
All coroutines 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.
270
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.Unconfined is a special dispatcher that also appears to run in the main thread, but it is, in fact, a different
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.Unconfined coroutine dispatcher starts coroutine in the caller thread, but only until the first suspension
point. After suspension it resumes in the thread that is fully determined by the suspending function that was invoked.
Unconfined dispatcher is appropriate when coroutine does not consume CPU time nor updates any shared data (like UI) that is
confined to a specific thread.
On the other side, by default, a dispatcher for the outer CoroutineScope is inherited. The default dispatcher for runBlocking
coroutine, in particular, is confined to the invoker thread, so inheriting it has the effect of confining execution to this thread
with a predictable FIFO scheduling.
So, the coroutine that had inherited context of runBlocking {...} continues to execute in the main thread, while the
unconfined one had resumed in the default executor thread that delay function is using.
Unconfined 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-effects, because some operation in a
coroutine must be performed right away. Unconfined 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 figure 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 file 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.
271
Run the following code with -Dkotlinx.coroutines.debug JVM option:
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 confined to the main thread. The output of
this code is:
The log function prints the name of the thread in square brackets and you can see, that it is the main thread, but the
identifier of the currently executing coroutine is appended to it. This identifier 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 specified 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:
272
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:
My job is "coroutine#1":BlockingCoroutine{Active}@6d311334
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
273
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:
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 specific request or doing some specific 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.
274
Combining context elements
Sometimes we need to define multiple elements for coroutine context. We can use + operator for that. For example, we can
launch a coroutine with an explicitly specified dispatcher and an explicitly specified name at the same time:
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:
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 different 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 confirm by noting that it does not print onto the screen anymore if we wait:
275
fun main(args: Array<String>) = runBlocking<Unit> {
val activity = Activity()
activity.create() // create an activity
activity.doSomething() // run test function
println("Launched coroutines")
delay(500L) // delay for half a second
println("Destroying activity!")
activity.destroy() // cancels all coroutines
delay(1000) // visually confirm that they don't work
}
Launched coroutines
Coroutine 0 is done
Coroutine 1 is done
Destroying activity!
As you can see, only the first 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.
For ThreadLocal, asContextElement extension function is here for the rescue. It creates an additional context element, which
keep the value of the given ThreadLocal and restores it every time the coroutine switches its context.
In this example we launch new coroutine in a background thread pool using Dispatchers.Default, so it works on a different
threads from a thread pool, but it still has the value of thread local variable, that we've specified using
threadLocal.asContextElement(value = "launch") , no matter on what thread the coroutine is executed. Thus, output
(with debug) is:
276
Pre-main, current thread: Thread[main @coroutine#1,5,main], thread local value: 'main'
Launch start, current thread: Thread[DefaultDispatcher-worker-1 @coroutine#2,5,main], thread local
value: 'launch'
After yield, current thread: Thread[DefaultDispatcher-worker-2 @coroutine#2,5,main], thread local value:
'launch'
Post-main, current thread: Thread[main @coroutine#1,5,main], thread local value: 'main'
ThreadLocal has first-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, is stored in a thread-
local variable. However, in this case you are fully responsible to synchronize potentially concurrent modifications 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.
277
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 flavors: 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.uncaughExceptionHandler , while the
latter are relying on the user to consume the final exception, for example via await or receive (produce and receive are covered
later in Channels section).
CoroutineExceptionHandler
278
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 redefine 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 specific handlers are registered. On Android, uncaughtExceptionPreHandler is installed as a global coroutine exception
handler.
CoroutineExceptionHandler is invoked only on exceptions which are not expected to be handled by the user, so registering it
in async builder and the like of it has no effect.
Caught java.lang.AssertionError
Cancellation is tightly bound with exceptions. Coroutines internally use CancellationException for cancellation, these
exceptions are ignored by all handlers, so they should be used only as the source of additional debug information, which can
be obtained by catch block. When a coroutine is cancelled using Job.cancel without a cause, it terminates, but it does not
cancel its parent. Cancelling without cause is a mechanism for parent to cancel its children without cancelling itself.
279
Cancelling child
Child is cancelled
Parent is not cancelled
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.
This also a reason why, in these examples, CoroutineExceptionHandler is always installed to a coroutine that is created in
GlobalScope. It does not make sense to install an exception handler to a coroutine that is launched in the scope of the
main runBlocking, since the main coroutine is going to be always cancelled when its child completes with exception
despite the installed handler.
Exceptions aggregation
What happens if multiple children of a coroutine throw an exception? The general rule is "the first exception wins", so the first
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.
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 delegate parts of its work to its children or not) to leak to its exception handler.
280
fun main(args: Array<String>) = runBlocking {
val handler = CoroutineExceptionHandler { _, exception ->
println("Caught $exception with suppressed ${exception.suppressed.contentToString()}")
}
val job = GlobalScope.launch(handler) {
launch {
try {
delay(Long.MAX_VALUE)
} finally {
throw ArithmeticException()
}
}
launch {
delay(100)
throw IOException()
}
delay(Long.MAX_VALUE)
}
job.join()
}
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 fixed
in the future.
281
Rethrowing CancellationException with original cause
Caught original java.io.IOException
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 defined in its scope. If any of UI's child task has failed,
it is not always necessary to cancel (effectively 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:
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.
282
fun main(args: Array<String>) = runBlocking {
try {
supervisorScope {
val child = launch {
try {
println("Child is sleeping")
delay(Long.MAX_VALUE)
} finally {
println("Child is cancelled")
}
}
// Give our child a chance to execute and print using yield
yield()
println("Throwing exception from scope")
throw AssertionError()
}
} catch(e: AssertionError) {
println("Caught assertion error")
}
}
Child is sleeping
Throwing exception from scope
Child is cancelled
Caught assertion error
Another crucial difference between regular and supervisor jobs is exception handling. Every child should handle its exceptions
by itself via exception handling mechanisms. This difference comes from the fact that child's failure is not propagated to the
parent.
Scope is completing
Child throws an exception
Caught java.lang.AssertionError
Scope is completed
283
Table of contents
— Select expression (experimental)
— Selecting from channels
— Selecting on close
— Selecting to send
— Selecting deferred values
— Switch over a channel of deferred values
Select expressions are an experimental feature of kotlinx.coroutines. Their API is expected to evolve in the upcoming
updates of the kotlinx.coroutines library with potentially breaking changes.
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:
284
The result of this code is:
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 specific action when the channel is closed. The following example also
shows that select is an expression that returns the result of its selected clause:
Let's use it with channel a that produces "Hello" string four times and channel b that produces "World" four times:
The result of this code is quite interesting, so we'll analyze it in mode detail:
285
First of all, select is biased to the first clause. When several clauses are selectable at the same time, the first one among
them gets selected. Here, both channels are constantly producing strings, so a channel, being the first clause in select, wins.
However, because we are using unbuffered 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:
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:
286
Let us start a dozen of them with a random delay.
Now the main function awaits for the first 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 specified string after a specified time:
287
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
288
Table of contents
— Shared mutable state and concurrency
— The problem
— Volatiles are of no help
— Thread-safe data structures
— Thread confinement fine-grained
— Thread confinement coarse-grained
— Mutual exclusion
— Actors
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.
var counter = 0
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:
289
val mtContext = newFixedThreadPoolContext(2, "mtPool") // explicitly define context with two threads
var counter = 0
There is common misconception that making a variable volatile solves concurrency problem. Let us try it:
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:
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 confinement is an approach to the problem of shared mutable state where all access to the particular shared state is
confined to a single thread. It is typically used in UI applications, where all UI state is confined to the single event-
dispatch/application thread. It is easy to apply with coroutines by using a
single-threaded context.
290
val counterContext = newSingleThreadContext("CounterContext")
var counter = 0
This code works very slowly, because it does fine-grained thread-confinement. Each individual increment switches from multi-
threaded Dispatchers.Default context to the single-threaded context using withContext block.
In practice, thread confinement is performed in large chunks, e.g. big pieces of state-updating business logic are confined 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 modifications 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 difference 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:
The locking in this example is fine-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 confined to.
291
Actors
An actor is an entity made up of a combination of a coroutine, the state that is confined 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 first step of using an actor is to define a class of messages that an actor is going to process. Kotlin's sealed classes are
well suited for that purpose. We define 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.
Then we define a function that launches an actor using an actor coroutine builder:
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 confinement of the state to the specific coroutine works as a solution to the problem of shared
mutable state. Indeed, actors may modify their own private state, but can only affect each other through messages (avoiding
the need for any locks).
Actor is more efficient than locking under load, because in this case it always has work to do and it does not have to switch to
a different 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.
292
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 specific 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 first paragraph of the documentation text (the block of text until the first 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
KDoc currently supports the following block tags:
@param <name>
Documents a value parameter of a function or a type parameter of a class, property or function. To better separate the
parameter name from the description, if you prefer, you can enclose the name of the parameter in brackets. The following two
syntaxes are therefore equivalent:
@return
293
Documents the return value of a function.
@constructor
@receiver
@property <name>
Documents the property of a class which has the specified name. This tag can be used for documenting properties declared
in the primary constructor, where putting a doc comment directly before the property definition 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 specified qualified 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 specified class or method to the See Also block of the documentation.
@author
@since
Specifies the version of the software in which the element being documented was introduced.
@suppress
Excludes the element from the generated documentation. Can be used for elements which are not part of the official 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:
If you want to specify a custom label for the link, use the Markdown reference-style syntax:
294
You can also use qualified names in the links. Note that, unlike JavaDoc, qualified names always use the dot character to
separate the components, even before a method name:
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 file, 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 specific overloaded
function is not required for the link to work.
Inside the file, the documentation for the module as a whole and for individual packages is introduced by the corresponding
first-level headings. The text of the heading must be "Module <module name> " for the module, and "Package <package
qualified name> " for a package.
# Module kotlin-demo
# Package org.jetbrains.kotlin.demo
## Level 2 heading
# Package org.jetbrains.kotlin.demo2
295
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.2.71"
}
Then add the respective dependencies using the kapt configuration in your dependencies block:
dependencies {
kapt 'groupId:artifactId:version'
}
If you previously used the Android support for annotation processors, replace usages of the annotationProcessor
configuration 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 configurations 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")
}
}
kapt {
javacOptions {
// Increase the max count of errors from annotation processors.
// Default is 100.
option("-Xmaxerrs", 500)
}
}
kapt {
correctErrorTypes = true
}
296
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 find 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 file using the Xplugin kotlinc option:
-Xplugin=$KOTLIN_HOME/lib/kotlin-annotation-processing.jar
— classes (required): An output path for the generated class files and resources.
— stubs (required): An output path for the stub files. In other words, some temporary directory.
— apclasspath (repeatable ): A path to the annotation processor JAR. Pass as many apclasspath options as many JARs you
have.
— apoptions : A base64-encoded list of the annotation processor options. See AP/javac options encoding for more
information.
— javacArguments : A base64-encoded list of the options passed to javac. See AP/javac options encoding for more
information.
— processors : A comma-specified list of annotation processor qualified class names. If specified, kapt does not try to find
annotation processors in apclasspath .
— aptMode (required)
297
— correctErrorTypes : See below. Disabled by default.
The plugin option format is: -P plugin:<plugin id>:<key>=<value> . Options can be repeated.
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
You can find the complete sample in the kotlin-examples Github repository.
Note that Kapt does not support multiple rounds for the generated Kotlin files.
oos.writeInt(options.size)
for ((key, value) in options.entries) {
oos.writeUTF(key)
oos.writeUTF(value)
}
oos.flush()
return Base64.getEncoder().encodeToString(os.toByteArray())
}
298
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 | Configure
Kotlin in Project action.
buildscript {
ext.kotlin_version = '1.2.71'
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.2.71"
}
The version should be literal in this block, and it cannot be applied from another build script.
plugins {
kotlin("jvm") version "1.2.71"
}
Kotlin sources can be mixed with Java sources in the same folder, or in different folders. The default convention is using
different folders:
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, configure source sets with java.sourceSets { ... } instead.
299
Targeting JavaScript
When targeting JavaScript, a different plugin should be applied:
This plugin only works for Kotlin files so it is recommended to keep Kotlin and Java files separate (if it's the case that the same
project contains Java files). 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 file, the plugin by default creates an additional JS file with binary descriptors. This file 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 different 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.2.71'
...
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
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 .
300
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 reflection or testing facilities, you need to add the corresponding dependencies as well:
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 files between
builds so only files affected by these changes would be compiled.
2. add -Pkotlin.incremental=true or -Pkotlin.incremental=false to Gradle command line parameters. Note that in this
case the parameter should be added to each subsequent build, and any build with disabled incremental compilation
invalidates incremental caches.
301
The Kotlin plugin supports Gradle Build Cache (Gradle version 4.3 and above is required; caching is disabled with lower
versions).
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 files that are not tracked by Gradle etc. To
enable caching for kapt anyway, add the following lines to the build script:
kapt {
useBuildCache = true
}
To disable the caching for all Kotlin tasks, set the system property flag 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 .
When targeting JavaScript, the tasks are called compileKotlin2Js and compileTestKotlin2Js respectively, and
compile<Name>Kotlin2Js for custom source sets.
compileKotlin {
kotlinOptions.suppressWarnings = true
}
compileKotlin {
kotlinOptions {
suppressWarnings = true
}
}
With Gradle Kotlin DSL, get the task from the project's tasks first:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
// ...
kotlinCompile.kotlinOptions.suppressWarnings = true
Use the types Kotlin2JsCompile and KotlinCompileCommon for the JS and Common targets, accordingly.
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile::class.java).all {
kotlinOptions { ... }
}
302
Attributes common for JVM and JS
Generating documentation
To generate documentation for Kotlin projects, use Dokka; please refer to the Dokka README for configuration 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 different possibilities of configuring the Gradle plugin:
303
— Kotlin
— Mixed Java and Kotlin
— Android
— JavaScript
304
Using Maven
Define the version of Kotlin you want to use via a kotlin.version property:
<properties>
<kotlin.version>1.2.71</kotlin.version>
</properties>
Dependencies
Kotlin has an extensive standard library that can be used in your applications. Configure the following dependency in the pom
file:
<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 reflection or testing facilities, you need to add the corresponding dependencies as well. The artifact
IDs are kotlin-reflect for the reflection 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>
305
<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>
306
<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
To make your builds faster, you can enable incremental compilation for Maven (supported since Kotlin 1.1.2). In order to do
that, define the kotlin.compiler.incremental property:
307
<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 off the warning, add the following block to your pom.xml file:
<configuration>
<experimentalCoroutines>enable</experimentalCoroutines>
</configuration>
Jar le
To create a small Jar file containing just the code from your module, include the following under build->plugins in your
Maven pom.xml file, where main.class is defined 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 file containing the code from your module along with dependencies, include the following under
build->plugins in your Maven pom.xml file, where main.class is defined as a property and points to the main Kotlin or Java
class:
308
<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 file 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>
<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.
309
Specifying compiler options
Additional options and arguments for the compiler can be specified as tags under the <configuration> element of the
Maven plugin node:
<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>
310
sourceMap
Name Property Generate source map
Description true, false values
Possible Default
false
name value
sourceMapEmbedSources Embed source files into source map "never", "always", "inlining"
"inlining"
sourceMapPrefix Prefix for paths in a source map
moduleKind Kind of a module generated by compiler "plain", "amd", "plain"
"commonjs", "umd"
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 configuration 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
311
Using Ant
These tasks are defined 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>
<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>
312
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>
<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
313
classpathref
Name Compilation
Descriptionclass path reference No
Required Default Value
includeRuntime If output is a .jar file, whether Kotlin runtime library is No true
included in the jar
moduleName Name of the module being compiled No The name of the target (if
specified) or the project
kotlin2js Attributes
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:
The full list of arguments that can be used is shown when you run kotlinc -help .
314
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
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.
315
Compiler Plugins
For instance, when you use Spring, you don't need all the classes to be open, but only classes annotated with specific
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.2.71"
}
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
Using in Maven
316
<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"
}
}
plugins {
id "org.jetbrains.kotlin.plugin.spring" version "1.2.71"
}
<compilerPlugins>
<plugin>spring</plugin>
</compilerPlugins>
The plugin specifies the following annotations: @Component, @Async, @Transactional, @Cacheable and @SpringBootTest.
Thanks to meta-annotations support classes annotated with @Configuration, @Controller, @RestController, @Service or
@Repository are automatically opened since these annotations are meta-annotated with @Component.
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.
317
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 file 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 reflection.
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
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.2.71"
}
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
318
<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 specifies @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.2.71"
}
<compilerPlugins>
<plugin>jpa</plugin>
</compilerPlugins>
Using in CLI
As with all-open, add the plugin JAR file 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
319
SAM-with-receiver compiler plugin
The sam-with-receiver compiler plugin makes the first parameter of the annotated Java "single abstract method" (SAM)
interface method a receiver in Kotlin. This conversion only works when the SAM interface is passed as a Kotlin lambda, both for
SAM adapters and SAM constructors (see the documentation for more details).
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
320
<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 file 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
321
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 different 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 official 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 affected 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
Di erences between "Kotlin Coding Conventions" and "IntelliJ IDEA default code style"
The most notable change is in the continuation indentation policy. There's a nice idea to use the double indent for showing
that a multi-line expression hasn't ended on the previous line. This is a very simple and general rule, but several Kotlin
constructions look a bit awkward when they are formatted this way. In Kotlin Coding Conventions it's recommended to use a
single indent in cases where the long continuation indent has been forced before
In practice, quite a bit of code is affected, 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.
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 effort. 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 files in several subsystems may produce merging
conflicts in personal branches. And while each conflict 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 files at once.
For medium and large projects the decision may be tough. If you are not ready to update many files right away you may decide
to migrate module by module, or continue with gradual migration for modified files only.
In order to share those changes for all project developers .idea/codeStyle folder have to be committed to VCS.
322
If an external build system is used for configuring 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=official property to the gradle.properties file at the project root and commit the file 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.
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 modified files" option, inspection will show formatting
problems only in modified files. Such files 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 configured with Gradle or Maven.
323
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 significant effort, 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.
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 definitely includes the following:
— Code that compiled and ran fine 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 differently, throwing an exception of a
different type than before, changing behavior observable only through reflection, changes in undocumented/undefined
behavior, renaming binary artifacts, etc. Sometimes such changes are very important and affect migration experience
dramatically, sometimes they are insignificant.
324
— Adding new warnings.
— Enabling new language constructs or relaxing limitations for existing ones.
— Changing private/internal APIs and other implementation details.
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
workflow 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 notified through Release notes of version A that a change is coming in version B.
Compilers are complicated software and despite the best effort 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 fix, because the fixes 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 fine, but now it won't any more), but we are
inclined to fixing 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 final 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 Jeffrey van Gogh, William R. Cook and Andrey Breslav).
The Language Committee makes final 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 fixes. 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
325
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 configuration.
Experimental features usually graduate to the stable status after some iterations.
To check the stability status of different 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 affect 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 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 flags (those that don't have the "-X" or "-XX" prefix) can be added only in feature releases and should be properly
deprecated before removing them. The "-X" and "-XX" flags are experimental and can be added and removed at any time.
Compatibility Tools
As legacy features get removed and bugs fixed, 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
326
We provide the -language-version and -api-version flags that make a new version emulate the behaviour of an old one, for
compatibility purposes. Normally, at least one previous version is supported. This effectively 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-reflect
with a newer compiler without specifying compatibility flags is not recommended, and the compiler will report a warning when
this happens.
Actively maintained code bases can benefit from getting bug fixes ASAP, without waiting for a full deprecation cycle to
complete. Currently such project can enable the -progressive flag and get such fixes enabled even in incremental releases.
All flags are available on the command line as well as Gradle and Maven.
Unlike sources that can be fixed 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.
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).
327
Stability of Di erent Components
There can be different 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.
— Additions in Incremental Releases (AIR): things can be added in an incremental release, removals and changes of
behavior should be avoided and announced in a previous incremental release if necessary.
— Stable Incremental Releases (SIR): incremental releases are fully compatible, only optimizations and bug fixes happen.
Any changes can be made in a feature release.
— Fully Stable (FS): incremental releases are fully compatible, feature releases are backwards compatible.
Source and binary compatibility may have different 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.
328
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 first official 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 first-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.
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
simplifies 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 first-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.
329
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 specific 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 definitions from
DefinitelyTyped 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 specific 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.
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-specific 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 or Basecamp.
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.
330
Are there any books on Kotlin?
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 Sommerhoff.
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, StackOverflow and more actively on
the Kotlin Slack (with close to 7000 members as of May 2017).
Yes. There are many User Groups and Meetups now focused exclusively around Kotlin. You can find a list on the web site. In
addition there are community organised Kotlin Nights events around the world.
Yes. The first official KotlinConf, taking place in San Francisco 2-3 November 2017. Kotlin is also being covered in different
conferences worldwide. You can find 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.
331
Comparison to Java Programming Language
332
333