Introduction
Kotlite is an open-sourced type-safe programming language that has a rich subset of the script variant of the Kotlin programming language. It comes with standard libraries, which are a subset of Kotlin Multiplatform/Common standard libraries and a few third-party libraries.
Kotlite Interpreter is a lightweight Kotlin Multiplatform library to interpret and execute codes written in Kotlite, and bridge the host runtime environment and the embedded runtime environment.
Major Features of Kotlite Interpreter
-
Supports a subset of Kotlin 1.9 language and standard libraries. Kotlin is a great, safe, descriptive and flexible language. Check the differences between Kotlite and Kotlin.
-
Supports writing complicated and generic code
-
Embeddable — it is a library
-
Safe
-
Classes from libraries or built-ins can be whitelisted or blacklisted
-
Extension functions from libraries or built-ins can be whitelisted or blacklisted
-
Extension properties from libraries or built-ins can be whitelisted or blacklisted
-
Global properties from libraries or built-ins can be whitelisted or blacklisted
-
No file or networking I/O or OS APIs in the standard library
-
-
Runs in multiplatform
-
Extensible and allows interaction with the host
-
Allows providing custom extension functions from the host
-
Allows providing custom extension properties from the host
-
Allows providing custom global properties from the host
-
Allows implementing custom libraries and delegating the calls to first-class Kotlin functions and properties
-
Allows reading values of global variables in the embedded environment from the host
-
Stdout pipe of the embedded environment is overridable
-
-
Lightweight —
kotlinc
is over 300 MB, and the sum of Kotlite with stdlib for all platforms is less than 10 MB. The JS script of the web demo is less than 800 KB. -
Semantic analysis, e.g. variable access and type verification, before execution
-
Type inference
-
Well tested — there are more than a thousand of hand-written unit tests per platform
-
Can be written in any IDE supporting Kotlin 1.9 — Kotlite does not create new syntax
To be honest, the standard library is not well tested. Only the language itself is well tested. Please kindly help to report if any issue is found. |
Supported Platforms
-
JVM (Java, Kotlin/JVM, …)
-
JS
-
Android (JVM)
-
iOS
-
macOS
-
watchOS
-
tvOS
The interpreter does not depend on any platform-specific APIs except the built-ins, so it should be easy for an experienced developer to port the library to any other platform supported by Kotlin Multiplatform.
Use Cases
Kotlite is designed for below use cases.
-
Executing user-provided simple expressions in a safe way
-
Executing user-provided script in a safe way
-
Allowing custom plugins, written as Kotlin codes, for any Kotlin or JVM applications in a safe way
-
Safely executing codes coming from servers
-
Updating mobile app UI any time without app update submissions to app store (this requires the community to contribute)
Non-goals
-
Kotlite does not replace Kotlin
-
Kotlite does not introduce new programming language features or syntax that are not provided in Kotlin, except necessaries supporting internal tools of Kotlite
Side Products
-
Rendering Kotlite codes as an AST (Abstract Syntax Tree) diagram using mermaid
-
Static analysis of Kotlite codes
-
Generating AST nodes from Kotlite codes
-
Reformatting Kotlite codes
Demo
Release Notes
Feature Requests or Reporting Issues
It is glad to have your contributions to this project by raising feature requests or reporting issues.
Please raise a ticket in the GitHub repository, if it has not been raised previously. Otherwise, vote that ticket.
For issue reporting, please include the following:
-
Minimal code that reproduces the issue
-
Platform language, OS and versions (e.g. JVM 21 on Windows)
-
Expected result
-
Actual result
Reported issues will be prioritized and addressed as soon as possible, according to importance, completeness and availability.
If you have any usage question, please visit the discussion section of the GitHub repository and search for if anyone has asked the same question previously. If there is none, please feel free to create a new discussion.
The Kotlite Interpreter
Getting Started
Include the dependencies
Firstly, include the dependencies.
Kotlite Interpreter
Kotlite Stdlib
For single platform:
dependencies {
implementation("io.github.sunny-chung:kotlite-interpreter:<version>")
implementation("io.github.sunny-chung:kotlite-stdlib:<version>")
// ...
}
For multiplatform:
kotlin {
sourceSets {
val commonMain by getting {
dependencies {
api("io.github.sunny-chung:kotlite-interpreter:<version>")
api("io.github.sunny-chung:kotlite-stdlib:<version>")
// ...
}
}
// ...
Stages
Developers should be familiar with most of the stages.
In the Semantic Analysis stage, it is doing lots of stuffs like checking whether a function in a class tries to override a non-existing function, returning values with a wrong data type, and inferring types, optimizing codes, etc..
Any stage can throw an exception.
The stages in different blocks do not require to be called immediately after the previous one.
Minimal Examples
After understanding the stages, we can start writing codes.
Print Hello world!
val env = ExecutionEnvironment().apply {
install(AllStdLibModules())
}
val interpreter = KotliteInterpreter(
filename = "Hello",
code = """
println("Hello world!")
""".trimIndent(),
executionEnvironment = env,
)
interpreter.eval()
Parsing and semantic analysis are performed in the function KotliteInterpreter() . It could be imagined as a "compilation process". If there is any error, an exception would be thrown from this function, before the eval() call.
|
The filename parameter is only used in error messages and stacktraces.
|
Retrieve global values of execution result
val env = ExecutionEnvironment().apply {
install(AllStdLibModules())
}
val interpreter = KotliteInterpreter(
filename = "Calculate",
code = """
val a = (1..10).fold(0) { acc, it ->
acc + it
}
""".trimIndent(),
executionEnvironment = env,
)
interpreter.eval()
val symbolTable = interpreter.symbolTable()
val a = (symbolTable.findPropertyByDeclaredName("a") as IntValue).value // 55
Evaluate an expression only
val env = ExecutionEnvironment().apply {
install(AllStdLibModules())
}
val result: IntValue = evalKotliteExpression(
filename = "Calculate",
code = "(1..10).fold(0) { acc, it -> acc + it }",
executionEnvironment = env,
) as IntValue
val a: Int = result.value // 55
Value and Type Classes
All the values returned by evalKotliteExpression()
or SymbolTable.findPropertyByDeclaredName()
or Interpreter.eval()
or value arguments provided to custom functions/properties are of a subtype of RuntimeValue
. Possible subtypes of RuntimeValue
are:
-
IntValue
-
LongValue
-
DoubleValue
-
CharValue
-
StringValue
-
BooleanValue
-
ByteValue
-
NullValue
-
UnitValue
-
LambdaValue
-
ThrowableValue
-
ClassInstance
RuntimeValue
has a member function type()
, which returns the type of the underlying value. The return type is a subtype of DataType
. DataType
is also provided when there are type arguments provided to custom functions/properties.
Possible subtypes of DataType
for consumer use are:
-
ObjectType
-
FunctionType
-
UnitType
-
NothingType
-
TypeParameterType
-
StarType
-
RepeatedType
In most of the time, ObjectType
would be returned. The underlying class definition, generic type arguments and nullabilities can be accessed in the ObjectType
class.
DataType
has a String member property descriptiveName
which returns a readable type name, for example, "MutableMap<MyPair<Int, Boolean>, List<String?>>?"
.
Thread Safety
The interpreter itself is not thread-safe. The code executed by the Kotlite interpreter cannot be on multiple threads.
However, Kotlite interpreter does not hold global states. Thus, it is possible to run different Interpreter instances and execute in multiple threads concurrently.
It might also work if mutex locks are enforced in provided custom functions.
Reusability
Most Kotlite classes cannot be reused, including ExecutionEnvironment
, AST nodes, parsers and the interpreter. They contain states. If one wants to repeat the execution or use the same inputs of ExecutionEnvironment
, they would have to duplicate the calls.
Security
Standard libraries delegations
The standard libraries are implemented as delegations to the original Kotlin / third-party APIs and classes in the host environment. For example, the implementation of the library function fun String.toRegex(): Regex
would convert the StringValue
to a real String
in the host environment, and then invoke toRegex()
, and return the Regex
instance back to the embedded environment in a wrapped form. The delegation approach can be a security concern.
While most of the Kotlite built-in standard libraries should be safe to execute, delegations to some third-party libraries might be unwanted.
Filtering classes, functions and properties
So, Kotlite provides a way to remove them from the embedded execution environment.
This can be done by supplying filter functions to ExecutionEnvironment
.
Built-in stuffs, e.g. Int
, can be filtered out as well, but that may cause troubles during code execution and importing libraries, and has no security benefits.
Below is an example to remove the class MutableList
completely without breaking the environment.
val env = ExecutionEnvironment(
classRegistrationFilter = {
it != "MutableList"
},
functionRegistrationFilter = {
!(it.receiverType ?: "").contains("MutableList") &&
!it.returnType.contains("MutableList")
},
).apply {
install(AllStdLibModules())
}
assertFailsWith<SemanticException> {
KotliteInterpreter(
filename = "<Test>",
code = """
val a = mutableListOf(1, 2, 3)
""".trimIndent(),
executionEnvironment = env
)
}
Developers can still create a class with the same name, as if the class never existed. This does no harm, as it does not interact with the host. |
Selectively installing libraries
It is possible to only install specific libraries to the ExecutionEnvironment
.
val env = ExecutionEnvironment().apply {
install(TextLibModule())
install(CollectionsLibModule())
install(ByteLibModule())
}
The order matters. If a library module depends on another one, the one being depended should be installed first.
Implicit code execution in equals()
, hashCode()
, toString()
, compareTo()
As mentioned previously, standard libraries are just delegations to the real APIs and classes.
To enable use cases like sorting a list of custom classes or using a custom class as keys of Map
, the functions equals()
, hashCode()
, toString()
, compareTo()
can be overridden by end users in Kotlite. In the host environment, calling these functions will execute the user-overridden codes and may throw exceptions. This may be an unwanted code execution and risk.
Bear in mind that doing a a == b
or "Debug: $a"
in your application may execute user code.
Resources Usage
There is no way to limit memory usage or computing resources of user code execution at this moment. User code can exhaust all the available memory or slow down the OS using infinite computing loops. This area might be improved in the future.
Integration with the Host
There are some APIs to allow the host provides custom executable functions and properties to the embedded script environment. These APIs are not yet stable and subject to change in the future.
Creating an integration is similar to creating a library module. It is recommended to read the details in the Creating Library Modules to have a deep understanding on this topic. |
Providing functions and extension Functions
To provide an extension function, use the ExecutionEnvironment.registerFunction(CustomFunctionDefinition)
API.
Below example provides an extension function with the signature fun String.size(factor: Int): Int
. The function also alters a variable hostVar
in the host environment before returning.
var hostVar: Int = 0
val env = ExecutionEnvironment().apply {
registerFunction(CustomFunctionDefinition(
receiverType = "String",
functionName = "size",
returnType = "Int",
parameterTypes = listOf(CustomFunctionParameter("factor", "Int")),
executable = { interpreter, receiver, args, typeArgs ->
IntValue((receiver as StringValue).value.length * (args[0] as IntValue).value, interpreter.symbolTable()).also {
hostVar = it.value
}
},
position = SourcePosition("MyBridge", 1, 1),
))
}
The value of position is used only when there is an error or runtime exception, in attempt to provide more information about the error.
|
To provide a global function, simply provide a null
value to the receiverType
parameter.
Providing extension properties
To provide an extension property, use the ExecutionEnvironment.registerExtensionProperty(ExtensionProperty)
API.
Below is an example exposing a host variable to the script environment to read and write values.
var hostScopeVariable = 0
val env = ExecutionEnvironment().apply {
registerExtensionProperty(ExtensionProperty(
declaredName = "f",
receiver = "String",
type = "Int",
getter = { interpreter, subject, typeArgs ->
IntValue(hostScopeVariable, interpreter.symbolTable())
},
setter = { interpreter, subject, value, typeArgs ->
hostScopeVariable += (value as IntValue).value
}
))
}
val interpreter = KotliteInterpreter(
filename = "MyScript",
code = """
val s = "abcde"
s.f = 10
val a = s.f // 10
s.f = 15
val b = s.f // 25
""".trimIndent(),
executionEnvironment = env,
)
interpreter.eval()
Either getter or setter parameter can be null if there is no getter or setter.
|
Providing global properties
The API to provide a global property is different from that for extension properties. It is ExecutionEnvironment.registerGlobalProperty(GlobalProperty)
.
var property = 10
val env = ExecutionEnvironment().apply {
registerGlobalProperty(GlobalProperty(
position = SourcePosition("MyScript", 1, 1),
declaredName = "x",
type = "Int",
isMutable = true,
getter = { interpreter -> IntValue(property, interpreter.symbolTable()) },
setter = { interpreter, value -> property = (value as IntValue).value },
))
registerGlobalProperty(GlobalProperty(
position = SourcePosition("Math", 1, 1),
declaredName = "myPi",
type = "Double",
isMutable = false,
getter = { interpreter -> DoubleValue(3.14, interpreter.symbolTable()) },
))
}
As seen in examples, either getter or setter can be optional (null ).
|
Executing other functions in executable
The APIs are less friendly, but this is possible.
Executing a lambda argument
The core stdlib has some good example.
CustomFunctionDefinition(
receiverType = "T",
functionName = "also",
returnType = "T",
typeParameters = listOf(TypeParameter(name = "T", typeUpperBound = null)),
parameterTypes = listOf(CustomFunctionParameter("block", "(T) -> Unit")),
executable = { interpreter, receiver, args, typeArgs ->
val block = args[0] as LambdaValue
block.execute(arrayOf(receiver))
receiver!!
},
position = SourcePosition(name, 1, 1),
),
CustomFunctionDefinition(
receiverType = "T",
functionName = "apply",
returnType = "T",
typeParameters = listOf(TypeParameter(name = "T", typeUpperBound = null)),
parameterTypes = listOf(CustomFunctionParameter("block", "T.() -> Unit")),
executable = { interpreter, receiver, args, typeArgs ->
val block = args[0] as LambdaValue
block.execute(arguments = emptyArray(), receiver = receiver!!)
receiver!!
},
position = SourcePosition(name, 1, 1),
),
The order matters. If A depends on B, put B before A. |
Executing other declared functions
This is not easy, and not a common use case. Take a look of /interpreter/src/commonMain/kotlin/com/sunnychung/lib/multiplatform/kotlite/model/SpecialFunction.kt for an example.
Creating Library Modules
A library module is just a collection of custom classes, functions, extension functions, extension properties and global properties.
The order matters. If A depends on B, put B before A. |
Kotlite Interpreter APIs
Let’s start with providing custom functions. Usually the process is like this:
In CustomFunctionDefinition
, the executable
lambda argument looks like this:
{ interpreter: Interpreter, receiver: RuntimeValue?, args: List<RuntimeValue>, typeArgs: Map<String, DataType> ->
// ...
}
The APIs and processes are similar for custom properties. This section applies to them as well. |
RuntimeValue — a Kotlite value that wraps a Kotlin value
In code level, a Kotlite value is a RuntimeValue
in the Kotlin host. Wrapping a Kotlin value to a RuntimeValue
is tricky. Below lists out how to wrap them.
Kotlin Type | Code to convert to a Kotlite value |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Non-generic object |
where |
Generic object |
where |
Object that is supported by the standard library |
Non-exhausted list:
Examples:
|
For nested classes such as List , Map or Pair , don’t forget to wrap all the nested values. Otherwise, the things would go wrong and exceptions may be thrown during code execution.
|
SymbolTable
A SymbolTable
can be obtained via Interpreter.symbolTable()
. SymbolTable
cannot be persisted, because it might be different in the context of another function call, and persisting it would lead to memory leak.
ClassDefinition and ProvidedClassDefinition
For types that are available from the standard libraries, usually it could be found by ${TypeName}Class.clazz
. For example, MutableListClass.clazz
for the class MutableList
.
For types that are not known to Kotlite, you will have to provide a custom ClassDefinition
.
ProvidedClassDefinition
is a friendly API for library users to define a class. It extends ClassDefinition
. An example can be found here.
DataType
If creation of generic Kotlite values is needed, for example, a List<T>
value, one or more DataType
are needed to specify the type arguments. It can be obtained from multiple ways.
-
If it is available in the type arguments of the function call, use
typeArgs[name]
.
For example, for a function signature like this:
fun <T, R : Comparable<R>> MutableList<T>.sortBy(selector: (T) -> R?)
typeArgs["T"]
is the T
type argument in DataType
, and typeArgs["R"]
is the R
type argument in DataType
.
-
Primitive data types
It can be obtained from SymbolTable
. For example, symbolTable.IntType
. For some special types like Any
, Unit
and Nothing
, it can be directly constructed: UnitType(isNullable: Boolean = false)
.
-
For other types, it can be obtained by the
String.toDataType(symbolTable: SymbolTable)
convenient extension function. For example,
val symbolTable: SymbolTable = interpreter.symbolTable()
val byteArrayType: DataType = "ByteArray".toDataType(symbolTable)
val pairType: DataType = "Pair<String, Pair<Double, Int>>".toDataType(symbolTable)
val genericType: DataType = "Map<K, Int>".toDataType(symbolTable)
If there is untrusted user input, this approach is vulnerable to injection attacks. |
Unwrapping Kotlite RuntimeValue
to a Kotlin value
It is relatively easy. Just cast to the right type and call the member property .value
.
Kotlin Type | Code to convert a Kotlite value to a Kotlin value |
---|---|
|
|
|
|
|
|
|
|
|
|
|
|
Object |
|
For nested classes such as List , Map or Pair , don’t forget to unwrap all the nested values if necessary.
|
Manual approach
Create a class that extends the abstract class LibraryModule
, give a name to it, include all the implementations, then this class is a Library Module that can be installed.
Taking this approach has the best performance, but requires lots of effort to write repetitive codes.
The IOLibModule
in the standard library is a good example to be referenced, because it is a library module completely written by hand.
IOLibModule
package com.sunnychung.lib.multiplatform.kotlite.stdlib
import com.sunnychung.lib.multiplatform.kotlite.model.CustomFunctionDefinition
import com.sunnychung.lib.multiplatform.kotlite.model.CustomFunctionParameter
import com.sunnychung.lib.multiplatform.kotlite.model.ExtensionProperty
import com.sunnychung.lib.multiplatform.kotlite.model.GlobalProperty
import com.sunnychung.lib.multiplatform.kotlite.model.LibraryModule
import com.sunnychung.lib.multiplatform.kotlite.model.ProvidedClassDefinition
import com.sunnychung.lib.multiplatform.kotlite.model.SourcePosition
import com.sunnychung.lib.multiplatform.kotlite.model.UnitValue
open class IOLibModule : LibraryModule("IO") {
override val classes: List<ProvidedClassDefinition> = emptyList()
override val properties: List<ExtensionProperty> = emptyList()
override val globalProperties: List<GlobalProperty> = emptyList()
override val functions: List<CustomFunctionDefinition> = listOf(
CustomFunctionDefinition(
receiverType = null,
functionName = "println",
returnType = "Unit",
parameterTypes = emptyList(),
executable = { interpreter, receiver, args, typeArgs ->
outputToConsole("\n")
UnitValue
},
position = SourcePosition(name, 1, 1),
),
CustomFunctionDefinition(
receiverType = null,
functionName = "println",
returnType = "Unit",
parameterTypes = listOf(CustomFunctionParameter("message", "Any?")),
executable = { interpreter, receiver, args, typeArgs ->
val message = args[0]
outputToConsole("${message.convertToString()}\n")
UnitValue
},
position = SourcePosition(name, 1, 1),
),
CustomFunctionDefinition(
receiverType = null,
functionName = "print",
returnType = "Unit",
parameterTypes = listOf(CustomFunctionParameter("message", "Any?")),
executable = { interpreter, receiver, args, typeArgs ->
val message = args[0]
outputToConsole(message.convertToString())
UnitValue
},
position = SourcePosition(name, 2, 1),
),
)
open fun outputToConsole(output: String) {
print(output)
}
}
Delegation approach
This approach is what the most Kotlite standard libraries take. Delegating everything to Kotlin, and generate all the delegation codes using the Kotlite Stdlib Processor Gradle plugin.
During the execution of the delegation call, Kotlite will unwrap the Kotlite RuntimeValue
to a Kotlin type if needed, execute the delegated function, and then wrap the result to a Kotlite RuntimeValue
. The time performance penalty is significant when the subject, argument or result is a Collection
with a large size.
Below is a minimal example to generate a delegation library module. Some stuffs from the Regex
and the Collection
library modules are taken in the example.
pluginManagement {
repositories {
mavenCentral()
// ...
}
}
Kotlite Library Preprocessor Gradle Plugin
plugins {
kotlin("multiplatform")
id("io.github.sunny-chung.kotlite-stdlib-processor-plugin") version "<version>"
}
// ...
kotlin {
sourceSets {
val commonMain by getting {
dependencies {
// ...
}
kotlin.srcDir(tasks.named("kotliteStdlibHeaderProcess").map { it.outputs })
}
// ...
kotliteStdLibHeaderProcessor {
inputDir = "src/kotlinheader/"
outputDir = "build/generated/common/"
outputPackage = "com.sunnychung.lib.multiplatform.kotlite.stdlib"
configs = mapOf(
"Regex" to KotliteModuleConfig(
imports = listOf(
"com.sunnychung.lib.multiplatform.kotlite.stdlib.regex.RegexClass",
"com.sunnychung.lib.multiplatform.kotlite.stdlib.regex.RegexValue",
)
),
)
}
Implement the delegated class and the value factory function.
fun RegexValue(value: Regex, symbolTable: SymbolTable) : DelegatedValue<Regex>
= DelegatedValue<Regex>(value, "Regex", RegexClass.clazz, symbolTable = symbolTable)
object RegexClass {
val clazz = ProvidedClassDefinition(
fullQualifiedName = "Regex",
typeParameters = emptyList(),
isInstanceCreationAllowed = true,
primaryConstructorParameters = listOf(CustomFunctionParameter("value", "String")),
constructInstance = { interpreter, callArguments, callPosition ->
RegexValue(Regex((callArguments[0] as StringValue).value), interpreter.symbolTable())
},
position = SourcePosition("Regex", 1, 1),
)
}
The factory function name has to be ${ActualTypeName}Value . It applies to any types, regardless of primitives or interfaces. This convention is hardcoded in the code generation plugin.
|
Create a Kotlin header file by writing every global or extension functions and extension properties that would be delegated, but without body. This file should be placed in /your-library/src/kotlinheader/${LibraryName}.kt
.
fun String.matches(regex: Regex): Boolean
fun String.replace(regex: Regex, replacement: String): String
fun String.replaceFirst(regex: Regex, replacement: String): String
fun String.toRegex(): Regex
val <T> List<T>.size: Int
get()
val <T> List<T>.lastIndex: Int
get()
Upon compilation, an abstract class Abstract${name}LibModule
would be generated. Examine if the generated code is compilable and correct. It can be checked by writing unit tests.
Example of generated code
/** Generated code. DO NOT MODIFY! Changes to this file will be overwritten. **/
package com.sunnychung.lib.multiplatform.kotlite.stdlib
import com.sunnychung.lib.multiplatform.kotlite.model.AnyType
import com.sunnychung.lib.multiplatform.kotlite.model.BooleanValue
import com.sunnychung.lib.multiplatform.kotlite.model.ByteValue
import com.sunnychung.lib.multiplatform.kotlite.model.ComparableRuntimeValue
import com.sunnychung.lib.multiplatform.kotlite.model.CustomFunctionDefinition
import com.sunnychung.lib.multiplatform.kotlite.model.CustomFunctionParameter
import com.sunnychung.lib.multiplatform.kotlite.model.CharValue
import com.sunnychung.lib.multiplatform.kotlite.model.DataType
import com.sunnychung.lib.multiplatform.kotlite.model.DelegatedValue
import com.sunnychung.lib.multiplatform.kotlite.model.DoubleValue
import com.sunnychung.lib.multiplatform.kotlite.model.ExtensionProperty
import com.sunnychung.lib.multiplatform.kotlite.model.FunctionModifier
import com.sunnychung.lib.multiplatform.kotlite.model.FunctionType
import com.sunnychung.lib.multiplatform.kotlite.model.GlobalProperty
import com.sunnychung.lib.multiplatform.kotlite.model.IntValue
import com.sunnychung.lib.multiplatform.kotlite.model.IterableValue
import com.sunnychung.lib.multiplatform.kotlite.model.IteratorClass
import com.sunnychung.lib.multiplatform.kotlite.model.IteratorValue
import com.sunnychung.lib.multiplatform.kotlite.model.KotlinValueHolder
import com.sunnychung.lib.multiplatform.kotlite.model.LambdaValue
import com.sunnychung.lib.multiplatform.kotlite.model.LibraryModule
import com.sunnychung.lib.multiplatform.kotlite.model.ListClass
import com.sunnychung.lib.multiplatform.kotlite.model.ListValue
import com.sunnychung.lib.multiplatform.kotlite.model.LongValue
import com.sunnychung.lib.multiplatform.kotlite.model.NothingType
import com.sunnychung.lib.multiplatform.kotlite.model.NullValue
import com.sunnychung.lib.multiplatform.kotlite.model.ObjectType
import com.sunnychung.lib.multiplatform.kotlite.model.PairClass
import com.sunnychung.lib.multiplatform.kotlite.model.PairValue
import com.sunnychung.lib.multiplatform.kotlite.model.PrimitiveIterableValue
import com.sunnychung.lib.multiplatform.kotlite.model.PrimitiveIteratorValue
import com.sunnychung.lib.multiplatform.kotlite.model.PrimitiveType
import com.sunnychung.lib.multiplatform.kotlite.model.PrimitiveTypeName
import com.sunnychung.lib.multiplatform.kotlite.model.ProvidedClassDefinition
import com.sunnychung.lib.multiplatform.kotlite.model.SourcePosition
import com.sunnychung.lib.multiplatform.kotlite.model.StringValue
import com.sunnychung.lib.multiplatform.kotlite.model.TypeParameter
import com.sunnychung.lib.multiplatform.kotlite.model.TypeParameterType
import com.sunnychung.lib.multiplatform.kotlite.model.RuntimeValue
import com.sunnychung.lib.multiplatform.kotlite.model.UnitType
import com.sunnychung.lib.multiplatform.kotlite.model.UnitValue
import com.sunnychung.lib.multiplatform.kotlite.util.wrapPrimitiveValueAsRuntimeValue
import com.sunnychung.lib.multiplatform.kotlite.stdlib.regex.RegexClass
import com.sunnychung.lib.multiplatform.kotlite.stdlib.regex.RegexValue
abstract class AbstractRegexLibModule : LibraryModule("Regex") {
override val classes = emptyList<ProvidedClassDefinition>()
override val properties = listOf<ExtensionProperty>(
)
override val globalProperties = emptyList<GlobalProperty>()
override val functions = listOf<CustomFunctionDefinition>(
CustomFunctionDefinition(
receiverType = "String",
functionName = "matches",
returnType = "Boolean",
parameterTypes = listOf(
CustomFunctionParameter(name = "regex", type = "Regex"),
),
typeParameters = emptyList(),
modifiers = setOf<FunctionModifier>(),
executable = { interpreter, receiver, args, typeArgs ->
val unwrappedReceiver = (receiver as StringValue).value
val regex_ = (args[0] as KotlinValueHolder<*>).value as Regex
val result = unwrappedReceiver.matches(regex_)
result?.let { BooleanValue(it /* _t = Boolean; t.name = Boolean; t = Boolean */, symbolTable = interpreter.symbolTable()) } ?: NullValue
},
position = SourcePosition(filename = "Regex", lineNum = 3, col = 1),
),
CustomFunctionDefinition(
receiverType = "String",
functionName = "replace",
returnType = "String",
parameterTypes = listOf(
CustomFunctionParameter(name = "regex", type = "Regex"),
CustomFunctionParameter(name = "replacement", type = "String"),
),
typeParameters = emptyList(),
modifiers = setOf<FunctionModifier>(),
executable = { interpreter, receiver, args, typeArgs ->
val unwrappedReceiver = (receiver as StringValue).value
val regex_ = (args[0] as KotlinValueHolder<*>).value as Regex
val replacement_ = (args[1] as StringValue).value
val result = unwrappedReceiver.replace(regex_, replacement_)
result?.let { StringValue(it /* _t = String; t.name = String; t = String */, symbolTable = interpreter.symbolTable()) } ?: NullValue
},
position = SourcePosition(filename = "Regex", lineNum = 4, col = 1),
),
CustomFunctionDefinition(
receiverType = "String",
functionName = "replaceFirst",
returnType = "String",
parameterTypes = listOf(
CustomFunctionParameter(name = "regex", type = "Regex"),
CustomFunctionParameter(name = "replacement", type = "String"),
),
typeParameters = emptyList(),
modifiers = setOf<FunctionModifier>(),
executable = { interpreter, receiver, args, typeArgs ->
val unwrappedReceiver = (receiver as StringValue).value
val regex_ = (args[0] as KotlinValueHolder<*>).value as Regex
val replacement_ = (args[1] as StringValue).value
val result = unwrappedReceiver.replaceFirst(regex_, replacement_)
result?.let { StringValue(it /* _t = String; t.name = String; t = String */, symbolTable = interpreter.symbolTable()) } ?: NullValue
},
position = SourcePosition(filename = "Regex", lineNum = 5, col = 1),
),
CustomFunctionDefinition(
receiverType = "String",
functionName = "toRegex",
returnType = "Regex",
parameterTypes = listOf(),
typeParameters = emptyList(),
modifiers = setOf<FunctionModifier>(),
executable = { interpreter, receiver, args, typeArgs ->
val unwrappedReceiver = (receiver as StringValue).value
val result = unwrappedReceiver.toRegex()
result?.let { RegexValue(it /* _t = Regex; t.name = Regex; t = Regex */, symbolTable = interpreter.symbolTable()) } ?: NullValue
},
position = SourcePosition(filename = "Regex", lineNum = 7, col = 1),
),
)
}
The code generation plugin has lots of hardcode. You may want to fork another one and add more hardcoded stuffs. |
Finally, create a class ${name}LibModule
extending this abstract class, override or add anything if necessary, then it is done.
package com.sunnychung.lib.multiplatform.kotlite.stdlib
import com.sunnychung.lib.multiplatform.kotlite.model.ProvidedClassDefinition
import com.sunnychung.lib.multiplatform.kotlite.stdlib.regex.RegexClass
class RegexLibModule : AbstractRegexLibModule() {
override val classes: List<ProvidedClassDefinition> = listOf(RegexClass.clazz)
}
Null values
In normal situations, a Kotlite null
value is mapped to a NullValue
before passing to the delegation calls. If the delegated function requires a real null
value to function correctly, for example, setOfNotNull()
or filterNotNull
, it is regarded as null-aware.
In this case, add a nullaware
modifier to these functions in the Kotlin header file, then the generated code would map NullValue
to null
. For example:
nullaware fun <T : Any> Iterable<T?>.filterNotNull(): List<T>
nullaware fun <T : Any> setOfNotNull(vararg elements: T?): Set<T>
Delegations to equals()
, hashCode()
, toString()
of Kotlin values
For security reasons, they are not delegated by default. An explicit delegation declaration is required.
For manual approach, below is an example to delegate CustomClass.toString()
.
val env = ExecutionEnvironment().apply {
registerClass(CustomClass.clazz)
registerFunction(CustomFunctionDefinition(
position = SourcePosition.NONE,
receiverType = "CustomClass",
functionName = "toString",
returnType = "String",
parameterTypes = emptyList(),
executable = { interpreter, receiver, args, typeArgs ->
StringValue((receiver as DelegatedValue<*>).value.toString(), interpreter.symbolTable())
}
))
}
For delegation approach, declare in the Kotlin header file. Below is an example to delegate KInstant.toString()
.
fun KInstant.toString(): String
Distribution
Kotlite does not provide a way to distribute or host libraries. Putting the source code in GitHub and creating an awesome-kotlite
repository might be an option.
Generating AST Diagrams
It is possible to generate mermaid code from Kotlite codes to render an AST diagram.
Below is an example.
val mermaidCode = kotliteAstNodeMermaidDiagram("""
val cache = mutableMapOf<Int, Long>()
fun fib(i: Int): Long {
if (i < 0) throw Exception("Invalid i: ${'$'}i")
if (i <= 1) return i.toLong()
if (i in cache) {
return cache[i]!!
}
return (fib(i - 2) + fib(i - 1)).also {
cache[i] = it
}
}
val a = fib(19) // 4181L
""".trimIndent())
println(mermaidCode, MermaidFlowchartDirection.LeftToRight)
For the above code snippet, after passing to mermaid, the generated diagram looks like this.
Advanced Usage
Tool Structure
There are several essential tools in Kotlite. The execution directions are roughly presented in this diagram.
Code Generator generates Kotlin codes with optionally debug information. It is mainly for debug purpose. |
The data directions are as follows:
All the tool classes are marked as open
. A developer may feel free to extend the tools to create new features.
AST Nodes
The Parser generates Abstract Syntax Tree (AST) nodes. The functions of the parser correspond to each syntax defined in the Kotlin grammar. The function name is the grammar name.
For example, calling Parser.script()
parses the code according to the script
definition in the Kotlin grammar, and Parser.type()
parses the code according to the type
syntax.
Below Kotlin code parses a type written in String to AST nodes that can be used by the Semantic Analyzer and other tools.
val simpleTypeNode: ASTNode = Parser(Lexer("(anything)", "Double")).type()
val complexTypeNode: ASTNode = Parser(Lexer("(anything)", "Map<String, MutableList<Pair<Int, Double>>>")).type()
val genericTypeNode: ASTNode = Parser(Lexer("(anything)", "Map<K, V>")).type()
val functionTypeNode: ASTNode = Parser(Lexer("(anything)", "Int.(T) -> Unit")).type()
Below Kotlin code parses an expression written in String to AST nodes that can be used by the Semantic Analyzer and other tools.
val expressionNode: ASTNode = Parser(Lexer("(anything)", "(1 + 2 * 3) / 4")).expression()
Pass it to the Semantic Analyzer and Interpreter and execute manually.
val executionEnvironment = ExecutionEnvironment()
SemanticAnalyzer(
rootNode = expressionNode,
executionEnvironment = executionEnvironment,
).analyze()
val result = Interpreter(
rootNode = expressionNode,
executionEnvironment = executionEnvironment,
).eval() as IntValue
val intResult: Int = result.value // 1
The Standard Library
At this moment, the Standard Library consists of following Kotlin/Common standard library modules:
-
kotlin
-
kotlin.collections
-
kotlin.io
-
kotlin.math
-
kotlin.ranges
-
kotlin.text
and the following external libraries:
Currently, not all of their functions and properties are imported, but it is planned to support all of them, as long as the inclusion does not bring security issues.
The standard library will be expanded as well. Regex matchers, encoding, hashing and crypto libraries are on the short-term goal list.
But file I/O and networking will not be available in the standard library due to potential security issues. Users who need them can implement a delegated library module.
Redirecting the stdout pipe
It is possible to redirect the stdout stream of the embedded script environment to somewhere else, for example, a StringBuilder
.
If IOLibModule
is installed manually, its member function outputToConsole
can be overridden.
val console = StringBuilder()
val env = ExecutionEnvironment().apply {
install(object : IOLibModule() {
override fun outputToConsole(output: String) {
console.append(output)
}
})
}
If AllStdLibModules
is installed instead, it accepts an optional constructor lambda parameter outputToConsoleFunction
.
val console = StringBuilder()
val env = ExecutionEnvironment().apply {
install(AllStdLibModules(outputToConsoleFunction = {
console.append(it)
}))
}
Known Issues or Limitations
There are some known issues that may not be tackled in short-term. They properly would be addressed in a later time, and might be improved bit by bit before fully addressed.
-
In a JVM with default JVM arguments, the depth of recursion calls only support up to about 140. Beyond that, "StackOverflowError" would be thrown.
-
Deep recursion calls use lots of memory and run slower
The Kotlite Language
Language
Kotlite parser implementation mostly conforms to the official Kotlin 1.9 documentation. Thus, the supported syntax and precedence resolutions are supposed to be equivalent to Kotlin 1.9.
Differences from Kotlin
Kotlin 1.9 | Kotlite Script | Kotlite API |
---|---|---|
Basic Data Types |
||
Byte |
✓ |
|
Short |
✕ |
|
Int |
✓ |
|
Long |
✓ |
|
Float |
✕ |
|
Double |
✓ |
|
Unsigned Numbers |
✕ |
|
Boolean |
✓ |
|
Char |
✓ |
|
String |
✓ |
|
Array |
Not supported except ByteArray. List is a replacement. |
|
Pair |
✓ |
|
Triple |
✕ |
|
Throwable |
✓ |
|
Unit |
✓ |
|
Literal Constants |
||
Decimals |
✓ |
|
Long - |
✓ |
|
Hex - |
✕ |
|
Binary - |
✕ |
|
|
✕ |
|
|
✕ |
|
Character escapes (\t, \b, \n, \r, \', \", \\, \$) |
✓ |
|
Unicode literal (e.g. \u0000) |
✓ |
|
UTF-16 surrogate pair characters in String literals |
✓ |
|
Multiline Strings (""") |
✓ |
|
String Templates ($) |
✓ |
|
Nested String Templates (e.g. |
✓ |
|
Syntax |
||
Using spaces and symbols in identifiers (e.g. variable/function names) |
✕ |
|
Single-line comment (//) |
✓ |
|
Block comments (/* … */) |
✓ |
|
Nested block comments |
✕ |
|
Extra new line characters within an expression |
✓ |
|
Operators |
||
Bitwise Operations (shl, shr, ushr, and, or, xor, inv) |
✕ |
|
Boolean Logic (&&, ||, !) |
✓ |
|
Arithmetics (+, -, *, /, %) |
✓ |
|
Comparisons (<, >, ⇐, >=) |
✓ |
|
Equality (==, !=) |
✓ |
|
Reference Equality (===, !==) |
✕ |
|
Type Checks (is, !is) |
✓ (with difference)Besides the root type, Kotlite checks whether all the type arguments are assignable to the subject’s one as well. Kotlin does not check. |
|
Type Casts (as, as?) |
||
In operators (in, !in) |
✓ |
|
To operator ( |
✓ |
|
Spread operator (*) |
✕ |
|
Control Flow |
||
If expressions |
✓ |
|
When expressions with optional |
✓ (with difference)Kotlite always requires an Kotlin does not require when it is not necessary. |
|
For loops |
✓ |
|
While loops |
✓ |
|
Do-while loops |
✓ |
|
Break and Continue |
✓ |
|
Normal Returns |
✓ |
|
Labelling loops |
✕ |
|
Automatic Labels for loops |
✕ |
|
Automatic Labels for lambdas |
✕ |
|
Manually labelling lambdas |
✓ |
|
Break and Continue Labels |
✕ |
|
Return to Labels |
✓ |
|
Return to functions outside enclosing inline functions |
✕ |
|
Throw exceptions |
✓ |
|
Try expressions |
✓ |
|
Try-catch-finally |
✓ |
|
Catch exceptions which are thrown outside interpreter scope |
✓ |
|
Properties |
||
val/var with optional initial values |
✓ |
|
Shadow variables |
✓ |
|
Custom getters and setters |
✕ |
✓ |
Backing fields for custom getters and setters |
✕ |
|
|
✕ |
|
Delegation ( |
✕ |
|
Destructuring declarations |
✕ |
|
Functions, Infix and Operator Functions |
||
Normal functions |
✓ |
|
Local functions |
✓ |
|
Value parameters with default expression |
✓ |
|
Named arguments |
✓ |
|
Single-expression functions (e.g. |
✓ |
|
Variable number of arguments ( |
✓ (with difference)In Kotlin, In Kotlite, it is provided as |
|
Overloading functions |
✓ |
|
Infix functions |
✓ |
|
Infix calls |
✓ |
|
Tail recursive functions ( |
✕ |
|
Inline functions |
✕ |
|
Overloading unary operators (, -, !, +, --) |
✕ |
|
Overloading arithmetic binary operators (+, -, *, /, %) |
✓ |
|
Overloading range operators (.., ..<) |
✓ |
|
Overloading "in" operators (in, !in) |
✓ |
|
Overloading indexed access operators ([], []=) |
✓ |
|
Overloading invoke operators ( |
✕ |
|
Overloading augmented assignments (+=, -=, *=, /=, %=) |
✓ |
|
Overloading equality operators (==, !=) |
✓ |
|
Overloading comparison operators (>, <, >=, ⇐) |
✓ |
|
Suspending functions |
✕ |
|
Packages and Imports |
✕ |
|
Class Foundations |
||
Primary constructor with optional val/var declarations |
✓ |
|
Secondary constructors |
✕ |
|
(Multiple) |
✓ |
|
Member properties |
✓ |
|
Member properties with custom getters and setters |
✓ |
|
Backing fields of member properties with custom getters and setters |
✕ |
|
Member functions |
✓ |
|
Overloading member functions |
✓ |
|
Visibility modifiers (public/private/protected/internal) |
✕ |
|
Reference to other classes that are declared after this class |
✕ |
|
Store companion object references into a field |
✕ |
|
Class Inheritance |
||
Passing values and type arguments to super class constructors |
✓ |
|
Inheriting members from super classes and interfaces |
✓ |
|
|
✓ |
|
|
✕ |
|
Overriding functions |
✓ (with difference)In Kotlin, default values and names of parameters of In Kotlite, it is possible. In the future, Kotlite may follow Kotlin. |
|
Overriding properties |
✓ |
|
Implicit |
✓ |
|
|
✓ |
|
Calling super functions |
✓ |
|
Calling super properties |
✓ |
|
Abstract functions |
✓ |
|
Abstract properties |
✕ |
|
Delegations |
✕ |
|
Overriding functions from the "Any" class |
✓ |
|
|
✕ |
|
|
✕ |
|
Class Variations |
||
Nested classes |
✕ |
|
Inner classes |
✕ |
|
Abstract classes |
✓ |
|
Sealed classes |
✕ |
|
Enum classes |
PartialIn Kotlite, only optional primary constructor with property declarations is supported. Other form of member declarations is not supported. For example, the following is supported:
|
|
Data classes |
✕ |
|
Value classes |
✕ |
|
Object classes |
✕ |
|
Companion objects |
Only available for extension functions and properties |
|
Annotation classes |
✕ |
|
Anonymous classes |
✕ |
|
Interfaces |
||
Abstract functions |
✓ |
|
Functions with body |
✕ |
|
Abstract properties |
✕ |
|
(Multiple) interfaces inheritance |
✓ |
|
Functional interfaces ( |
✕ |
|
Sealed interfaces |
✕ |
|
Extensions |
||
Extension functions |
✓ |
|
Extension operator functions |
✓ |
|
Extension properties |
✕ |
✓ |
Nullable receiver extensions |
✓ |
|
Companion object extensions |
✓ |
|
Generic type parameter as the receiver of extension functions (e.g. |
✓ |
|
Extension functions as class members |
✓ |
|
Resolving calls to extension functions of super classes/interfaces |
✓ |
|
Generics |
||
Type parameters in classes |
✓ |
|
Type parameters in interfaces |
✓ |
|
Type parameters in non-class functions |
✓ |
|
Type parameters in (generic) class member functions |
✓ |
|
Type parameters in extension functions |
✓ |
|
Nested generic types |
✓ |
|
Use type parameter as receiver of extension functions |
✕ |
|
|
✕ |
|
Star projection ( |
✓ |
|
Upper bounds of type parameters (e.g. |
✓ |
|
Recursive upper bounds of type parameters (e.g. |
✓ |
|
Definitely non-nullable types (e.g. |
✕ |
|
|
✕ |
|
Type erasure |
DifferentIn Kotlin, type argument is not preserved. In Kotlite, it is behaved as if type argument is erased, but it is preserved in runtime. |
|
Unchecked casts |
✓ |
|
Underscore as type arguments |
✕ |
|
Reified type parameters |
No as there is no type erasure |
|
Type Alias |
✕ |
|
Null Safety |
||
Nullable types (e.g. |
✓ |
|
Non-nullable types (e.g. |
✓ |
|
Safe call operator ( |
✓ |
|
Elvis operator ( |
✓ |
|
NPE operator ( |
✓ |
|
Safe casts ( |
✓ |
|
Lambdas and Higher-order Functions |
||
Lambda expressions |
✓ |
|
Anonymous functions |
✕ |
|
Returning and storing lambda literals |
✓ |
|
Passing trailing lambdas to functions |
✓ |
|
Implicit single parameter |
✓ |
|
Underscore as unused variable names |
✓ |
|
Destructuring value arguments in lambdas |
✕ |
|
Accessing variables and functions declared in the enclosing closures |
✓ |
|
Nested lambdas |
✓ |
|
Labelling lambdas |
✓ |
|
Function types with receiver in function value parameters (e.g. |
✓ |
|
Function literials with receiver (e.g. |
✕ |
|
Function reference ( |
✕ |
|
Checking Before Execution |
||
Type checking |
✓ |
|
Checking of non-exist variables, functions or classes |
✓ |
|
Checking of illegal writes to read-only properties |
✓ |
|
Checking of ambiguous function calls |
✓ |
|
Checking of type arguments not conforming to upper bound conditions |
✓ |
|
Detect incompatible types on |
✕ |
|
Type Inference |
||
Types of property declarations (val/var) |
✓ |
|
Return types of if and when expressions |
✓ |
|
Return types of single-expression functions |
✓ |
|
Infer lambda vaule parameter types |
✓ |
|
Infer lambda return types |
✓ |
|
Type arguments of generic function calls |
✓ |
|
Type arguments of generic class constructors |
✓ |
|
Receiver of generic extension functions |
✓ |
|
Infer nested types recursively |
✓ |
|
Cyclic type inference error detection |
✓ |
|
Identify a nullable type is non-nullable after asserting it is non-null |
✕ |
|
Identify a super type is a subtype after asserting it is a subtype |
✕ |
|
Unwrap types of unnecessary safe call operator ( |
✕ |
|
Annotations |
✕ |
|
Reflection |
✕ |
|
Coroutines |
✕ |
|
Asynchronous Programming |
✕ |
|
Interoperability with Java and other languages |
✕ |
Runtime Behaviour Differences
Code | Kotlin 1.9 | Kotlite |
---|---|---|
Generics with
as? operator
|
Throws exception:
|
Output:
|
Generics with
as? operator
|
Output:
|
Output:
|
Property resolutions in local classes
|
Output:
|
Output:
|
Intended Differences
In Kotlin, member functions always have a higher priority than extension functions.
Currently, since the only way to provide custom class functions in Kotlite is to provide extension functions, extension functions with below signatures are treated as special functions and have a higher priority than member functions. Return types are not in consideration in the process of identifying special functions.
fun equals(Any?)
fun hashCode()
fun toString()
Built-in and Standard Library APIs
Built-in
Types
Any
open class Any
Comparable
interface Comparable<T>
Throwable
open class Throwable constructor(message: String? = null, cause: Throwable? = null)
Int
class Int : Comparable<Int>
Double
class Double : Comparable<Double>
Long
class Long : Comparable<Long>
Boolean
class Boolean : Comparable<Boolean>
String
class String : Comparable<String>
Char
class Char : Comparable<Char>
Byte
class Byte
Unit
class Unit
Nothing
class Nothing
Function
class Function
Class
class Class<T : Any>
Pair
class Pair<A, B> constructor(first: A, second: B)
Exception
open class Exception constructor(message: String? = null, cause: Throwable? = null)
NullPointerException
class NullPointerException constructor(message: String? = null, cause: Throwable? = null)
TypeCastException
class TypeCastException constructor(valueType: String, targetType: String)
Iterator
interface Iterator<T>
Iterable
interface Iterable<T>
PrimitiveIterator
interface PrimitiveIterator<T> : Iterator<T>
PrimitiveIterable
interface PrimitiveIterable<T> : Iterable<T>
Collection
interface Collection<T> : Iterable<T>
List
class List<T> : Collection<T>
Extension Properties
val <A, B> Pair<A, B>.first: A get()
val <A, B> Pair<A, B>.second: B get()
val Throwable.message: String? get()
val Throwable.cause: Throwable? get()
val Throwable.name: String get()
Extension Functions
fun Throwable.stackTraceToString(): String
operator fun <T> Iterator<T>.hasNext(): Boolean
operator fun <T> Iterator<T>.next(): T
fun <T> Iterable<T>.iterator(): Iterator<T>
operator fun <T> PrimitiveIterator<T>.hasNext(): Boolean
operator fun <T> PrimitiveIterator<T>.next(): T
fun <T> PrimitiveIterable<T>.iterator(): PrimitiveIterator<T>
Core
Global Functions
fun <R> run(block: () -> R): R
fun <T, R> with(receiver: T, block: T.() -> R): R
fun repeat(times: Int, action: (Int) -> Unit): Unit
fun TODO(): Nothing
fun check(value: Boolean): Unit
fun check(value: Boolean, lazyMessage: () -> Any): Unit
fun <T : Any> checkNotNull(value: T?): T
fun <T : Any> checkNotNull(value: T?, lazyMessage: () -> Any): T
fun require(value: Boolean): Unit
fun require(value: Boolean, lazyMessage: () -> Any): Unit
fun <T : Any> requireNotNull(value: T?): T
fun <T : Any> requireNotNull(value: T?, lazyMessage: () -> Any): T
Extension Functions
fun <T> T.also(block: (T) -> Unit): T
fun <T> T.apply(block: T.() -> Unit): T
fun <T, R> T.let(block: (T) -> R): R
fun <T, R> T.run(block: T.() -> R): R
fun Double.isFinite(): Boolean
fun Double.isInfinite(): Boolean
fun Double.isNaN(): Boolean
fun Int.toLong(): Long
fun Int.toDouble(): Double
fun Long.toInt(): Int
fun Long.toDouble(): Double
fun Double.toInt(): Int
fun Double.toLong(): Long
fun <T> Pair<T, T>.toList(): List<T>
fun <T> T.takeIf(predicate: (T) -> Boolean): T?
fun <T> T.takeUnless(predicate: (T) -> Boolean): T?
IO
Global Functions
fun println(): Unit
fun println(message: Any?): Unit
fun print(message: Any?): Unit
Collections
Types
MutableCollection
interface MutableCollection<T> : Collection<T>
MutableList
class MutableList<T> : MutableCollection<T>
Map
class Map<K, V>
MutableMap
class MutableMap<K, V>
MapEntry
class MapEntry<K, V>
Set
class Set<T> : Collection<T>
MutableSet
class MutableSet<T> : MutableCollection<T>
Extension Properties
val <T> List<T>.size: Int get()
val <T> List<T>.lastIndex: Int get()
val <K, V> Map<K, V>.size: Int get()
val <K, V> Map<K, V>.keys: Collection<K> get()
val <K, V> Map<K, V>.values: Collection<V> get()
val <K, V> MapEntry<K, V>.key: K get()
val <K, V> MapEntry<K, V>.value: V get()
val <T> Set<T>.size: Int get()
Global Functions
fun <T> listOf(vararg elements: T): List<T>
fun <T> mutableListOf(vararg elements: T): MutableList<T>
fun <T : Any> listOfNotNull(vararg elements: T?): List<T>
fun <T> List(size: Int, init: (Int) -> T): List<T>
fun <T> MutableList(size: Int, init: (Int) -> T): MutableList<T>
fun <K, V> mapOf(vararg pairs: Pair<K, V>): Map<K, V>
fun <K, V> mutableMapOf(vararg pairs: Pair<K, V>): MutableMap<K, V>
fun <T> mutableSetOf(vararg elements: T): MutableSet<T>
fun <T> setOf(vararg elements: T): Set<T>
fun <T : Any> setOfNotNull(vararg elements: T?): Set<T>
Extension Functions
fun <T> MutableCollection<T>.add(element: T): Boolean
fun <T> MutableCollection<T>.addAll(elements: Iterable<T>): Boolean
fun <T> Iterable<T>.all(predicate: (T) -> Boolean): Boolean
fun <T> Iterable<T>.any(predicate: (T) -> Boolean): Boolean
fun <T> List<T>.asReversed(): List<T>
fun <T : Comparable<T>> List<T?>.binarySearch(element: T?, fromIndex: Int = 0, toIndex: Int = size): Int
fun <T> List<T>.binarySearch(fromIndex: Int = 0, toIndex: Int = size, comparison: (T) -> Int): Int
fun <T, K : Comparable<K>> List<T>.binarySearchBy(key: K?, fromIndex: Int = 0, toIndex: Int = size, selector: (T) -> K?): Int
fun <T, R> Iterable<T>.chunked(size: Int, transform: (List<T>) -> R): List<R>
operator fun <T> Iterable<T>.contains(element: T): Boolean
fun <T> List<T>.containsAll(elements: List<T>): Boolean
fun <T> MutableCollection<T>.clear(): Unit
fun <T> Iterable<T>.count(predicate: (T) -> Boolean): Int
fun <T> Iterable<T>.count(): Int
fun <T> Iterable<T>.distinct(): List<T>
fun <T, K> Iterable<T>.distinctBy(selector: (T) -> K): List<T>
fun <T> Iterable<T>.drop(n: Int): List<T>
fun <T> List<T>.dropLast(n: Int): List<T>
fun <T> List<T>.dropLastWhile(predicate: (T) -> Boolean): List<T>
fun <T> Iterable<T>.dropWhile(predicate: (T) -> Boolean): List<T>
fun <T> Iterable<T>.elementAt(index: Int): T
fun <T> Iterable<T>.elementAtOrElse(index: Int, defaultValue: (Int) -> T): T
fun <T> Iterable<T>.elementAtOrNull(index: Int): T?
fun <T> MutableList<T>.fill(value: T): Unit
fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T>
fun <T> Iterable<T>.filterIndexed(predicate: (Int, T) -> Boolean): List<T>
fun <T> Iterable<T>.filterNot(predicate: (T) -> Boolean): List<T>
fun <T : Any> Iterable<T?>.filterNotNull(): List<T>
fun <T> Iterable<T>.find(predicate: (T) -> Boolean): T?
fun <T> Iterable<T>.findLast(predicate: (T) -> Boolean): T?
fun <T> Iterable<T>.first(): T
fun <T> Iterable<T>.first(predicate: (T) -> Boolean): T
fun <T, R : Any> Iterable<T>.firstNotNullOf(transform: (T) -> R?): R
fun <T, R : Any> Iterable<T>.firstNotNullOfOrNull(transform: (T) -> R?): R?
fun <T> Iterable<T>.firstOrNull(): T?
fun <T> Iterable<T>.firstOrNull(predicate: (T) -> Boolean): T?
fun <T, R> Iterable<T>.flatMap(transform: (T) -> Iterable<R>): List<R>
fun <T, R> Iterable<T>.flatMapIndexed(transform: (Int, T) -> Iterable<R>): List<R>
fun <T, R> Iterable<T>.fold(initial: R, operation: (R, T) -> R): R
fun <T, R> Iterable<T>.foldIndexed(initial: R, operation: (Int, R, T) -> R): R
fun <T, R> List<T>.foldRight(initial: R, operation: (T, R) -> R): R
fun <T, R> List<T>.foldRightIndexed(initial: R, operation: (Int, T, R) -> R): R
fun <T> Iterable<T>.forEach(action: (T) -> Unit): Unit
fun <T> Iterable<T>.forEachIndexed(action: (Int, T) -> Unit): Unit
operator fun <T> List<T>.get(index: Int): T
fun <T> List<T>.getOrElse(index: Int, defaultValue: (Int) -> T): T
fun <T> List<T>.getOrNull(index: Int): T?
fun <T> Iterable<T>.indexOf(element: T): Int
fun <T> Iterable<T>.indexOfFirst(predicate: (T) -> Boolean): Int
fun <T> Iterable<T>.indexOfLast(predicate: (T) -> Boolean): Int
fun <T> List<T>.isEmpty(): Boolean
fun <T> List<T>.isNotEmpty(): Boolean
fun <T> List<T>?.isNullOrEmpty(): Boolean
fun <T> Iterable<T>.joinToString(separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -(1), truncated: String = "...", transform: (T) -> String = null): String
fun <T> Iterable<T>.last(): T
fun <T> Iterable<T>.last(predicate: (T) -> Boolean): T
fun <T> Iterable<T>.lastIndexOf(element: T): Int
fun <T> Iterable<T>.lastOrNull(): T?
fun <T> Iterable<T>.lastOrNull(predicate: (T) -> Boolean): T?
fun <T, R> Iterable<T>.map(transform: (T) -> R): List<R>
fun <T, R> Iterable<T>.mapIndexed(transform: (Int, T) -> R): List<R>
fun <T, R : Any> Iterable<T>.mapIndexedNotNull(transform: (Int, T) -> R?): List<R>
fun <T, R : Any> Iterable<T>.mapNotNull(transform: (T) -> R?): List<R>
fun <T : Comparable<T>> Iterable<T>.max(): T
fun <T, R : Comparable<R>> Iterable<T>.maxBy(selector: (T) -> R): T
fun <T, R : Comparable<R>> Iterable<T>.maxByOrNull(selector: (T) -> R): T?
fun <T, R : Comparable<R>> Iterable<T>.maxOf(selector: (T) -> R): R
fun <T, R : Comparable<R>> Iterable<T>.maxOfOrNull(selector: (T) -> R): R?
fun <T : Comparable<T>> Iterable<T>.maxOrNull(): T?
fun <T : Comparable<T>> Iterable<T>.min(): T
fun <T, R : Comparable<R>> Iterable<T>.minBy(selector: (T) -> R): T
fun <T, R : Comparable<R>> Iterable<T>.minByOrNull(selector: (T) -> R): T?
fun <T, R : Comparable<R>> Iterable<T>.minOf(selector: (T) -> R): R
fun <T, R : Comparable<R>> Iterable<T>.minOfOrNull(selector: (T) -> R): R?
fun <T : Comparable<T>> Iterable<T>.minOrNull(): T?
operator fun <T> Iterable<T>.minus(element: T): List<T>
operator fun <T> Iterable<T>.minus(elements: Iterable<T>): List<T>
operator fun <T> MutableCollection<T>.minusAssign(element: T): Unit
operator fun <T> MutableCollection<T>.minusAssign(elements: Iterable<T>): Unit
fun <T> Iterable<T>.minusElement(element: T): List<T>
fun <T> Iterable<T>.none(predicate: (T) -> Boolean): Boolean
fun <T> Iterable<T>.none(): Boolean
fun <T, C : Iterable<T>> C.onEach(action: (T) -> Unit): C
fun <T> List<T>.onEachIndexed(action: (Int, T) -> Unit): List<T>
fun <T> List<T>?.orEmpty(): List<T>
fun <T> Iterable<T>.partition(predicate: (T) -> Boolean): Pair<List<T>, List<T>>
operator fun <T> Iterable<T>.plus(element: T): List<T>
operator fun <T> Iterable<T>.plus(elements: List<T>): List<T>
operator fun <T> MutableCollection<T>.plusAssign(element: T): Unit
operator fun <T> MutableCollection<T>.plusAssign(elements: Iterable<T>): Unit
fun <T> Iterable<T>.plusElement(element: T): List<T>
fun <T> List<T>.random(): T
fun <T> List<T>.randomOrNull(): T?
fun <T> MutableCollection<T>.remove(element: T): Boolean
fun <T> MutableCollection<T>.removeAll(elements: Collection<T>): Boolean
fun <T> MutableList<T>.removeAll(predicate: (T) -> Boolean): Boolean
fun <T> MutableList<T>.removeAt(index: Int): T
fun <T> MutableList<T>.removeFirst(): T
fun <T> MutableList<T>.removeFirstOrNull(): T?
fun <T> MutableList<T>.removeLast(): T
fun <T> MutableList<T>.removeLastOrNull(): T?
fun <T> MutableCollection<T>.retainAll(elements: Collection<T>): Boolean
fun <T> MutableList<T>.retainAll(predicate: (T) -> Boolean): Boolean
fun <T> Iterable<T>.reversed(): List<T>
fun <T, R> Iterable<T>.scan(initial: R, operation: (R, T) -> R): List<R>
fun <T, R> Iterable<T>.scanIndexed(initial: R, operation: (Int, R, T) -> R): List<R>
operator fun <T> MutableList<T>.set(index: Int, element: T): T
fun <T> MutableList<T>.shuffle(): Unit
fun <T> Iterable<T>.shuffled(): List<T>
fun <T> Iterable<T>.single(): T
fun <T> Iterable<T>.single(predicate: (T) -> Boolean): T
fun <T> Iterable<T>.singleOrNull(): T?
fun <T> Iterable<T>.singleOrNull(predicate: (T) -> Boolean): T?
fun <T : Comparable<T>> MutableList<T>.sort(): Unit
fun <T, R : Comparable<R>> MutableList<T>.sortBy(selector: (T) -> R?): Unit
fun <T, R : Comparable<R>> MutableList<T>.sortByDescending(selector: (T) -> R?): Unit
fun <T : Comparable<T>> MutableList<T>.sortDescending(): Unit
fun <T : Comparable<T>> Iterable<T>.sorted(): List<T>
fun <T, R : Comparable<R>> Iterable<T>.sortedBy(selector: (T) -> R?): List<T>
fun <T, R : Comparable<R>> Iterable<T>.sortedByDescending(selector: (T) -> R?): List<T>
fun <T : Comparable<T>> Iterable<T>.sortedDescending(): List<T>
fun <T> List<T>.subList(fromIndex: Int, toIndex: Int): List<T>
fun <T> Iterable<T>.take(n: Int): List<T>
fun <T> List<T>.takeLast(n: Int): List<T>
fun <T> List<T>.takeLastWhile(predicate: (T) -> Boolean): List<T>
fun <T> Iterable<T>.takeWhile(predicate: (T) -> Boolean): List<T>
fun <T> Iterable<T>.toList(): List<T>
fun <T> Iterable<T>.toMutableList(): MutableList<T>
fun <T, R> Iterable<Pair<T, R>>.unzip(): Pair<List<T>, List<R>>
fun <T, R> Iterable<T>.windowed(size: Int, step: Int = 1, partialWindows: Boolean = false, transform: (List<T>) -> R): List<R>
infix fun <T, R> Iterable<T>.zip(other: Iterable<R>): List<Pair<T, R>>
fun <T, R, V> Iterable<T>.zip(other: Iterable<R>, transform: (T, R) -> V): List<V>
operator fun <K, V> Map<K, V>.contains(key: K): Boolean
fun <K> Map<K, *>.containsKey(key: K): Boolean
fun <K, V> Map<K, V>.containsValue(value: V): Boolean
operator fun <K, V> Map<K, V>.iterator(): Iterator<MapEntry<K, V>>
fun <K, V> Map<K, V>.all(predicate: (MapEntry<K, V>) -> Boolean): Boolean
fun <K, V> Map<K, V>.any(): Boolean
fun <K, V> Map<K, V>.any(predicate: (MapEntry<K, V>) -> Boolean): Boolean
fun <T, K, V> Iterable<T>.associate(transform: (T) -> Pair<K, V>): Map<K, V>
fun <T, K> Iterable<T>.associateBy(keySelector: (T) -> K): Map<K, T>
fun <K, V> Iterable<K>.associateBy(valueSelector: (K) -> V): Map<K, V>
fun <K, V> Iterable<K>.associateWith(valueSelector: (K) -> V): Map<K, V>
fun <K, V> MutableMap<K, V>.clear(): Unit
fun <K, V> Map<K, V>.count(): Int
fun <K, V> Map<K, V>.count(predicate: (MapEntry<K, V>) -> Boolean): Int
fun <K, V> Map<K, V>.filter(predicate: (MapEntry<K, V>) -> Boolean): Map<K, V>
fun <K, V> Map<K, V>.filterKeys(predicate: (K) -> Boolean): Map<K, V>
fun <K, V> Map<K, V>.filterNot(predicate: (MapEntry<K, V>) -> Boolean): Map<K, V>
fun <K, V> Map<K, V>.filterValues(predicate: (V) -> Boolean): Map<K, V>
fun <K, V, R : Any> Map<K, V>.firstNotNullOf(transform: (MapEntry<K, V>) -> R?): R
fun <K, V, R : Any> Map<K, V>.firstNotNullOfOrNull(transform: (MapEntry<K, V>) -> R?): R?
fun <K, V, R> Map<K, V>.flatMap(transform: (MapEntry<K, V>) -> Iterable<R>): List<R>
fun <K, V> Map<K, V>.forEach(action: (MapEntry<K, V>) -> Unit): Unit
operator fun <K, V> Map<K, V>.get(key: K): V?
fun <K, V> Map<K, V>.getOrElse(key: K, defaultValue: () -> V): V
fun <K, V> MutableMap<K, V>.getOrPut(key: K, defaultValue: () -> V): V
fun <K, V> Map<K, V>.getValue(key: K): V
fun <T, K> Iterable<T>.groupBy(keySelector: (T) -> K): Map<K, List<T>>
fun <T, K, V> Iterable<T>.groupBy(keySelector: (T) -> K, valueSelector: (T) -> V): Map<K, List<V>>
fun <K, V> Map<K, V>.isNotEmpty(): Boolean
fun <K, V> Map<K, V>?.isNullOrEmpty(): Boolean
fun <K, V, R> Map<K, V>.map(transform: (MapEntry<K, V>) -> R): List<R>
fun <K, V, R> Map<K, V>.mapKeys(transform: (MapEntry<K, V>) -> R): Map<R, V>
fun <K, V, R : Any> Map<K, V>.mapNotNull(transform: (MapEntry<K, V>) -> R?): List<R>
fun <K, V, R> Map<K, V>.mapValues(transform: (MapEntry<K, V>) -> R): Map<K, R>
fun <K, V, R : Comparable<R>> Map<K, V>.maxBy(selector: (MapEntry<K, V>) -> R): MapEntry<K, V>
fun <K, V, R : Comparable<R>> Map<K, V>.maxByOrNull(selector: (MapEntry<K, V>) -> R): MapEntry<K, V>?
fun <K, V, R : Comparable<R>> Map<K, V>.maxOf(selector: (MapEntry<K, V>) -> R): R
fun <K, V, R : Comparable<R>> Map<K, V>.maxOfOrNull(selector: (MapEntry<K, V>) -> R): R?
fun <K, V, R : Comparable<R>> Map<K, V>.minBy(selector: (MapEntry<K, V>) -> R): MapEntry<K, V>
fun <K, V, R : Comparable<R>> Map<K, V>.minByOrNull(selector: (MapEntry<K, V>) -> R): MapEntry<K, V>?
fun <K, V, R : Comparable<R>> Map<K, V>.minOf(selector: (MapEntry<K, V>) -> R): R
fun <K, V, R : Comparable<R>> Map<K, V>.minOfOrNull(selector: (MapEntry<K, V>) -> R): R?
operator fun <K, V> Map<K, V>.minus(key: K): Map<K, V>
operator fun <K, V> Map<K, V>.minus(keys: List<K>): Map<K, V>
operator fun <K, V> MutableMap<K, V>.minusAssign(key: K): Unit
operator fun <K, V> MutableMap<K, V>.minusAssign(keys: List<K>): Unit
fun <K, V> Map<K, V>.none(): Boolean
fun <K, V> Map<K, V>.none(predicate: (MapEntry<K, V>) -> Boolean): Boolean
fun <K, V, M : Map<K, V>> M.onEach(action: (MapEntry<K, V>) -> Unit): M
fun <K, V> Map<K, V>.onEachIndexed(action: (Int, MapEntry<K, V>) -> Unit): Map<K, V>
fun <K, V> MutableMap<K, V>.onEachIndexed(action: (Int, MapEntry<K, V>) -> Unit): MutableMap<K, V>
fun <K, V> Map<K, V>?.orEmpty(): Map<K, V>
operator fun <K, V> Map<K, V>.plus(pair: Pair<K, V>): Map<K, V>
operator fun <K, V> Map<K, V>.plus(pairs: List<Pair<K, V>>): Map<K, V>
operator fun <K, V> MutableMap<K, V>.plusAssign(pair: Pair<K, V>): Unit
operator fun <K, V> MutableMap<K, V>.plusAssign(pairs: List<Pair<K, V>>): Unit
fun <K, V> MutableMap<K, V>.put(key: K, value: V): V?
fun <K, V> MutableMap<K, V>.putAll(pairs: List<Pair<K, V>>): Unit
fun <K, V> MutableMap<K, V>.remove(key: K): V?
operator fun <K, V> MutableMap<K, V>.set(key: K, value: V): Unit
fun <K, V> Map<K, V>.toList(): List<Pair<K, V>>
fun <K, V> Iterable<Pair<K, V>>.toMap(): Map<K, V>
fun <K, V> Map<K, V>.toMap(): Map<K, V>
fun <K, V> Map<K, V>.toMutableMap(): MutableMap<K, V>
fun <K, V> Map<K, V>.withDefault(defaultValue: (K) -> V): Map<K, V>
fun <K, V> MutableMap<K, V>.withDefault(defaultValue: (K) -> V): MutableMap<K, V>
operator fun <T> Set<T>.contains(element: T): Boolean
fun <T> Set<T>.containsAll(elements: Collection<T>): Boolean
fun <T> Set<T>.isEmpty(): Boolean
operator fun <T> Set<T>.iterator(): Iterator<T>
infix fun <T> Iterable<T>.intersect(other: Iterable<T>): Set<T>
operator fun <T> Set<T>.minus(element: T): Set<T>
operator fun <T> Set<T>.minus(elements: Iterable<T>): Set<T>
fun <T> Set<T>.minusElement(element: T): Set<T>
fun <T> Set<T>?.orEmpty(): Set<T>
operator fun <T> Set<T>.plus(element: T): Set<T>
operator fun <T> Set<T>.plus(elements: Iterable<T>): Set<T>
fun <T> Set<T>.plusElement(element: T): Set<T>
infix fun <T> Iterable<T>.subtract(other: Iterable<T>): Set<T>
fun <T> Iterable<T>.toMutableSet(): MutableSet<T>
fun <T> Iterable<T>.toSet(): Set<T>
infix fun <T> Iterable<T>.union(other: Iterable<T>): Set<T>
fun <T> MutableSet<T>.add(element: T): Boolean
fun <T> MutableSet<T>.addAll(elements: Collection<T>): Boolean
fun <T> MutableSet<T>.clear(): Unit
fun <T> MutableSet<T>.remove(element: T): Boolean
fun <T> MutableSet<T>.removeAll(elements: Collection<T>): Boolean
fun <T> MutableSet<T>.retainAll(elements: Collection<T>): Boolean
fun <T> PrimitiveIterable<T>.all(predicate: (T) -> Boolean): Boolean
fun <T> PrimitiveIterable<T>.any(predicate: (T) -> Boolean): Boolean
fun <T, R> PrimitiveIterable<T>.chunked(size: Int, transform: (List<T>) -> R): List<R>
operator fun <T> PrimitiveIterable<T>.contains(element: T): Boolean
fun <T> PrimitiveIterable<T>.count(predicate: (T) -> Boolean): Int
fun <T> PrimitiveIterable<T>.count(): Int
fun <T> PrimitiveIterable<T>.distinct(): List<T>
fun <T, K> PrimitiveIterable<T>.distinctBy(selector: (T) -> K): List<T>
fun <T> PrimitiveIterable<T>.drop(n: Int): List<T>
fun <T> PrimitiveIterable<T>.dropWhile(predicate: (T) -> Boolean): List<T>
fun <T> PrimitiveIterable<T>.elementAt(index: Int): T
fun <T> PrimitiveIterable<T>.elementAtOrElse(index: Int, defaultValue: (Int) -> T): T
fun <T> PrimitiveIterable<T>.elementAtOrNull(index: Int): T?
fun <T> PrimitiveIterable<T>.filter(predicate: (T) -> Boolean): List<T>
fun <T> PrimitiveIterable<T>.filterIndexed(predicate: (Int, T) -> Boolean): List<T>
fun <T> PrimitiveIterable<T>.filterNot(predicate: (T) -> Boolean): List<T>
fun <T> PrimitiveIterable<T>.find(predicate: (T) -> Boolean): T?
fun <T> PrimitiveIterable<T>.findLast(predicate: (T) -> Boolean): T?
fun <T> PrimitiveIterable<T>.first(): T
fun <T> PrimitiveIterable<T>.first(predicate: (T) -> Boolean): T
fun <T, R : Any> PrimitiveIterable<T>.firstNotNullOf(transform: (T) -> R?): R
fun <T, R : Any> PrimitiveIterable<T>.firstNotNullOfOrNull(transform: (T) -> R?): R?
fun <T> PrimitiveIterable<T>.firstOrNull(): T?
fun <T> PrimitiveIterable<T>.firstOrNull(predicate: (T) -> Boolean): T?
fun <T, R> PrimitiveIterable<T>.flatMap(transform: (T) -> Iterable<R>): List<R>
fun <T, R> PrimitiveIterable<T>.flatMapIndexed(transform: (Int, T) -> Iterable<R>): List<R>
fun <T, R> PrimitiveIterable<T>.fold(initial: R, operation: (R, T) -> R): R
fun <T, R> PrimitiveIterable<T>.foldIndexed(initial: R, operation: (Int, R, T) -> R): R
fun <T> PrimitiveIterable<T>.forEach(action: (T) -> Unit): Unit
fun <T> PrimitiveIterable<T>.forEachIndexed(action: (Int, T) -> Unit): Unit
fun <T> PrimitiveIterable<T>.indexOf(element: T): Int
fun <T> PrimitiveIterable<T>.indexOfFirst(predicate: (T) -> Boolean): Int
fun <T> PrimitiveIterable<T>.indexOfLast(predicate: (T) -> Boolean): Int
fun <T> PrimitiveIterable<T>.joinToString(separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -(1), truncated: String = "...", transform: (T) -> String = null): String
fun <T> PrimitiveIterable<T>.last(): T
fun <T> PrimitiveIterable<T>.last(predicate: (T) -> Boolean): T
fun <T> PrimitiveIterable<T>.lastIndexOf(element: T): Int
fun <T> PrimitiveIterable<T>.lastOrNull(): T?
fun <T> PrimitiveIterable<T>.lastOrNull(predicate: (T) -> Boolean): T?
fun <T, R> PrimitiveIterable<T>.map(transform: (T) -> R): List<R>
fun <T, R> PrimitiveIterable<T>.mapIndexed(transform: (Int, T) -> R): List<R>
fun <T, R : Any> PrimitiveIterable<T>.mapIndexedNotNull(transform: (Int, T) -> R?): List<R>
fun <T, R : Any> PrimitiveIterable<T>.mapNotNull(transform: (T) -> R?): List<R>
fun <T : Comparable<T>> PrimitiveIterable<T>.max(): T
fun <T, R : Comparable<R>> PrimitiveIterable<T>.maxBy(selector: (T) -> R): T
fun <T, R : Comparable<R>> PrimitiveIterable<T>.maxByOrNull(selector: (T) -> R): T?
fun <T, R : Comparable<R>> PrimitiveIterable<T>.maxOf(selector: (T) -> R): R
fun <T, R : Comparable<R>> PrimitiveIterable<T>.maxOfOrNull(selector: (T) -> R): R?
fun <T : Comparable<T>> PrimitiveIterable<T>.maxOrNull(): T?
fun <T : Comparable<T>> PrimitiveIterable<T>.min(): T
fun <T, R : Comparable<R>> PrimitiveIterable<T>.minBy(selector: (T) -> R): T
fun <T, R : Comparable<R>> PrimitiveIterable<T>.minByOrNull(selector: (T) -> R): T?
fun <T, R : Comparable<R>> PrimitiveIterable<T>.minOf(selector: (T) -> R): R
fun <T, R : Comparable<R>> PrimitiveIterable<T>.minOfOrNull(selector: (T) -> R): R?
fun <T : Comparable<T>> PrimitiveIterable<T>.minOrNull(): T?
operator fun <T> PrimitiveIterable<T>.minus(element: T): List<T>
operator fun <T> PrimitiveIterable<T>.minus(elements: PrimitiveIterable<T>): List<T>
fun <T> PrimitiveIterable<T>.minusElement(element: T): List<T>
fun <T> PrimitiveIterable<T>.none(predicate: (T) -> Boolean): Boolean
fun <T> PrimitiveIterable<T>.none(): Boolean
fun <T> PrimitiveIterable<T>.partition(predicate: (T) -> Boolean): Pair<List<T>, List<T>>
operator fun <T> PrimitiveIterable<T>.plus(element: T): List<T>
operator fun <T> PrimitiveIterable<T>.plus(elements: List<T>): List<T>
fun <T> PrimitiveIterable<T>.plusElement(element: T): List<T>
fun <T> PrimitiveIterable<T>.reversed(): List<T>
fun <T, R> PrimitiveIterable<T>.scan(initial: R, operation: (R, T) -> R): List<R>
fun <T, R> PrimitiveIterable<T>.scanIndexed(initial: R, operation: (Int, R, T) -> R): List<R>
fun <T> PrimitiveIterable<T>.shuffled(): List<T>
fun <T> PrimitiveIterable<T>.single(): T
fun <T> PrimitiveIterable<T>.single(predicate: (T) -> Boolean): T
fun <T> PrimitiveIterable<T>.singleOrNull(): T?
fun <T> PrimitiveIterable<T>.singleOrNull(predicate: (T) -> Boolean): T?
fun <T : Comparable<T>> PrimitiveIterable<T>.sorted(): List<T>
fun <T, R : Comparable<R>> PrimitiveIterable<T>.sortedBy(selector: (T) -> R?): List<T>
fun <T, R : Comparable<R>> PrimitiveIterable<T>.sortedByDescending(selector: (T) -> R?): List<T>
fun <T : Comparable<T>> PrimitiveIterable<T>.sortedDescending(): List<T>
fun <T> PrimitiveIterable<T>.take(n: Int): List<T>
fun <T> PrimitiveIterable<T>.takeWhile(predicate: (T) -> Boolean): List<T>
fun <T> PrimitiveIterable<T>.toList(): List<T>
fun <T> PrimitiveIterable<T>.toMutableList(): MutableList<T>
fun <T, R> PrimitiveIterable<T>.windowed(size: Int, step: Int = 1, partialWindows: Boolean = false, transform: (List<T>) -> R): List<R>
infix fun <T, R> PrimitiveIterable<T>.zip(other: PrimitiveIterable<R>): List<Pair<T, R>>
fun <T, R, V> PrimitiveIterable<T>.zip(other: PrimitiveIterable<R>, transform: (T, R) -> V): List<V>
fun <T, K, V> PrimitiveIterable<T>.associate(transform: (T) -> Pair<K, V>): Map<K, V>
fun <T, K> PrimitiveIterable<T>.associateBy(keySelector: (T) -> K): Map<K, T>
fun <K, V> PrimitiveIterable<K>.associateBy(valueSelector: (K) -> V): Map<K, V>
fun <K, V> PrimitiveIterable<K>.associateWith(valueSelector: (K) -> V): Map<K, V>
fun <T, K> PrimitiveIterable<T>.groupBy(keySelector: (T) -> K): Map<K, List<T>>
fun <T, K, V> PrimitiveIterable<T>.groupBy(keySelector: (T) -> K, valueSelector: (T) -> V): Map<K, List<V>>
infix fun <T> PrimitiveIterable<T>.intersect(other: PrimitiveIterable<T>): Set<T>
infix fun <T> PrimitiveIterable<T>.subtract(other: PrimitiveIterable<T>): Set<T>
fun <T> PrimitiveIterable<T>.toMutableSet(): MutableSet<T>
fun <T> PrimitiveIterable<T>.toSet(): Set<T>
infix fun <T> PrimitiveIterable<T>.union(other: PrimitiveIterable<T>): Set<T>
Text
Extension Properties
val String.length: Int get()
val String.lastIndex: Int get()
Extension Functions
fun String.all(predicate: (Char) -> Boolean): Boolean
fun String.any(predicate: (Char) -> Boolean): Boolean
fun String.commonPrefixWith(other: String, ignoreCase: Boolean = false): String
fun String.commonSuffixWith(other: String, ignoreCase: Boolean = false): String
fun String.compareTo(other: String, ignoreCase: Boolean = false): Int
fun String.contains(other: String, ignoreCase: Boolean = false): Boolean
fun String.contains(other: Char, ignoreCase: Boolean = false): Boolean
fun String.count(): Int
fun String.drop(n: Int): String
fun String.dropLast(n: Int): String
fun String.dropLastWhile(predicate: (Char) -> Boolean): String
fun String.dropWhile(predicate: (Char) -> Boolean): String
fun String.endsWith(suffix: String, ignoreCase: Boolean = false): Boolean
fun String?.equals(other: String?, ignoreCase: Boolean = false): Boolean
fun String.filter(predicate: (Char) -> Boolean): String
fun String.filterIndexed(predicate: (Int, Char) -> Boolean): String
fun String.filterNot(predicate: (Char) -> Boolean): String
fun String.first(): Char
fun String.firstOrNull(): Char?
fun String.forEach(action: (Char) -> Unit): Unit
fun String.forEachIndexed(action: (Int, Char) -> Unit): Unit
fun String.getOrElse(index: Int, defaultValue: (Int) -> Char): Char
fun String.getOrNull(index: Int): Char?
fun String.indexOf(string: String, startIndex: Int = 0, ignoreCase: Boolean = false): Int
fun String.indexOfFirst(predicate: (Char) -> Boolean): Int
fun String.indexOfLast(predicate: (Char) -> Boolean): Int
fun String.isBlank(): Boolean
fun String.isEmpty(): Boolean
fun String.isNotBlank(): Boolean
fun String.isNotEmpty(): Boolean
fun String?.isNullOrBlank(): Boolean
fun String?.isNullOrEmpty(): Boolean
fun String.last(): Char
fun String.lastIndexOf(string: String, startIndex: Int = lastIndex, ignoreCase: Boolean = false): Int
fun String.lastOrNull(): Char?
fun String.lowercase(): String
fun String.none(predicate: (Char) -> Boolean): Boolean
fun String?.orEmpty(): String
fun String.padEnd(length: Int, padChar: Char = ' '): String
fun String.padStart(length: Int, padChar: Char = ' '): String
fun String.prependIndent(indent: String = " "): String
fun String.random(): Char
fun String.randomOrNull(): Char?
fun String.removePrefix(prefix: String): String
fun String.removeRange(startIndex: Int, endIndex: Int): String
fun String.removeSuffix(suffix: String): String
fun String.removeSurrounding(prefix: String, suffix: String): String
fun String.repeat(n: Int): String
fun String.replace(oldValue: Char, newValue: Char, ignoreCase: Boolean = false): String
fun String.replace(oldValue: String, newValue: String, ignoreCase: Boolean = false): String
fun String.replaceAfter(delimiter: String, replacement: String, missingDelimiterValue: String = this): String
fun String.replaceAfterLast(delimiter: String, replacement: String, missingDelimiterValue: String = this): String
fun String.replaceBefore(delimiter: String, replacement: String, missingDelimiterValue: String = this): String
fun String.replaceBeforeLast(delimiter: String, replacement: String, missingDelimiterValue: String = this): String
fun String.replaceFirst(oldValue: String, newValue: String, ignoreCase: Boolean = false): String
fun String.replaceRange(startIndex: Int, endIndex: Int, replacement: String): String
fun String.reversed(): String
fun String.single(): Char
fun String.singleOrNull(): Char?
fun String.startsWith(prefix: String, ignoreCase: Boolean = false): Boolean
fun String.substring(startIndex: Int, endIndex: Int = length): String
fun String.substringAfter(delimiter: String, missingDelimiterValue: String = this): String
fun String.substringAfterLast(delimiter: String, missingDelimiterValue: String = this): String
fun String.substringBefore(delimiter: String, missingDelimiterValue: String = this): String
fun String.substringBeforeLast(delimiter: String, missingDelimiterValue: String = this): String
fun String.take(n: Int): String
fun String.takeLast(n: Int): String
fun String.takeLastWhile(predicate: (Char) -> Boolean): String
fun String.takeWhile(predicate: (Char) -> Boolean): String
fun String?.toBoolean(): Boolean
fun String.toBooleanStrictOrNull(): Boolean?
fun String.toDouble(): Double
fun String.toDoubleOrNull(): Double?
fun String.toInt(): Int
fun String.toInt(radix: Int): Int
fun String.toIntOrNull(): Int?
fun String.toIntOrNull(radix: Int): Int?
fun String.trim(): String
fun String.trimEnd(): String
fun String.trimStart(): String
fun String.uppercase(): String
fun Char.isDefined(): Boolean
fun Char.isDigit(): Boolean
fun Char.isHighSurrogate(): Boolean
fun Char.isISOControl(): Boolean
fun Char.isLetter(): Boolean
fun Char.isLetterOrDigit(): Boolean
fun Char.isLowerCase(): Boolean
fun Char.isLowSurrogate(): Boolean
fun Char.isSurrogate(): Boolean
fun Char.isUpperCase(): Boolean
fun Char.isWhitespace(): Boolean
fun Char.lowercase(): String
fun Char.lowercaseChar(): Char
fun Char.uppercase(): String
fun Char.uppercaseChar(): Char
Regex
Types
Regex
class Regex constructor(value: String)
Extension Functions
fun String.matches(regex: Regex): Boolean
fun String.replace(regex: Regex, replacement: String): String
fun String.replaceFirst(regex: Regex, replacement: String): String
fun String.toRegex(): Regex
Math
Global Properties
val E: Double
val PI: Double
Extension Properties
val Double.absoluteValue: Double get()
val Int.absoluteValue: Int get()
val Long.absoluteValue: Long get()
val Double.sign: Double get()
val Int.sign: Int get()
val Long.sign: Int get()
Global Functions
fun abs(x: Double): Double
fun abs(x: Int): Int
fun abs(x: Long): Long
fun acos(x: Double): Double
fun acosh(x: Double): Double
fun asin(x: Double): Double
fun asinh(x: Double): Double
fun atan(x: Double): Double
fun atan2(y: Double, x: Double): Double
fun atanh(x: Double): Double
fun cbrt(x: Double): Double
fun ceil(x: Double): Double
fun cos(x: Double): Double
fun cosh(x: Double): Double
fun exp(x: Double): Double
fun expm1(x: Double): Double
fun floor(x: Double): Double
fun hypot(x: Double, y: Double): Double
fun ln(x: Double): Double
fun ln1p(x: Double): Double
fun log(x: Double, base: Double): Double
fun log10(x: Double): Double
fun log2(x: Double): Double
fun max(a: Double, b: Double): Double
fun max(a: Int, b: Int): Int
fun max(a: Long, b: Long): Long
fun min(a: Double, b: Double): Double
fun min(a: Int, b: Int): Int
fun min(a: Long, b: Long): Long
fun round(x: Double): Double
fun sign(x: Double): Double
fun sin(x: Double): Double
fun sinh(x: Double): Double
fun sqrt(x: Double): Double
fun tan(x: Double): Double
fun tanh(x: Double): Double
fun truncate(x: Double): Double
Extension Functions
fun Double.nextDown(): Double
fun Double.nextTowards(to: Double): Double
fun Double.nextUp(): Double
fun Double.pow(x: Double): Double
fun Double.pow(n: Int): Double
fun Double.roundToInt(): Int
fun Double.roundToLong(): Long
fun Double.withSign(sign: Double): Double
fun Double.withSign(sign: Int): Double
Byte
Types
ByteArray
class ByteArray
Extension Properties
val ByteArray.lastIndex: Int get()
val ByteArray.size: Int get()
Global Functions
fun byteArrayOf(vararg elements: Byte): ByteArray
Extension Functions
fun Int.toByte(): Byte
fun Long.toByte(): Byte
fun Byte.toInt(): Int
fun Byte.toLong(): Long
fun Byte.toDouble(): Double
fun Byte.toChar(): Char
fun ByteArray.asList(): List<Byte>
fun ByteArray.average(): Double
infix fun ByteArray?.contentEquals(other: ByteArray?): Boolean
fun ByteArray?.contentToString(): String
fun ByteArray.firstOrNull(predicate: (Byte) -> Boolean): Byte?
fun ByteArray?.contentHashCode(): Int
fun ByteArray.copyOf(): ByteArray
fun ByteArray.copyOf(newSize: Int): ByteArray
fun ByteArray.copyOfRange(fromIndex: Int, toIndex: Int): ByteArray
fun ByteArray.count(): Int
fun ByteArray.drop(n: Int): List<Byte>
fun ByteArray.dropLast(n: Int): List<Byte>
fun ByteArray.fill(element: Byte, fromIndex: Int = 0, toIndex: Int = size): Unit
fun ByteArray.forEach(action: (Byte) -> Unit): Unit
fun ByteArray.forEachIndexed(action: (Int, Byte) -> Unit): Unit
fun ByteArray.first(): Byte
operator fun ByteArray.get(index: Int): Byte
operator fun ByteArray.iterator(): Iterator<Byte>
fun ByteArray.getOrElse(index: Int, defaultValue: (Int) -> Byte): Byte
fun ByteArray.getOrNull(index: Int): Byte?
fun ByteArray.indexOf(element: Byte): Int
fun ByteArray.indexOfFirst(predicate: (Byte) -> Boolean): Int
fun ByteArray.indexOfLast(predicate: (Byte) -> Boolean): Int
fun ByteArray.joinToString(separator: String = ", ", prefix: String = "", postfix: String = "", limit: Int = -(1), truncated: String = "...", transform: (Byte) -> String = null): String
fun ByteArray.last(): Byte
fun <R> ByteArray.map(transform: (Byte) -> R): List<R>
fun <R> ByteArray.mapIndexed(transform: (Int, Byte) -> R): List<R>
fun ByteArray.max(): Byte
fun ByteArray.min(): Byte
fun ByteArray.none(): Boolean
fun ByteArray.onEach(action: (Byte) -> Unit): ByteArray
fun ByteArray.onEachIndexed(action: (Int, Byte) -> Unit): ByteArray
operator fun ByteArray.plus(element: Byte): ByteArray
operator fun ByteArray.plus(elements: ByteArray): ByteArray
fun ByteArray.random(): Byte
fun ByteArray.randomOrNull(): Byte?
fun ByteArray.reverse(): Unit
fun ByteArray.reversed(): List<Byte>
fun ByteArray.reversedArray(): ByteArray
operator fun ByteArray.set(index: Int, value: Byte): Unit
fun ByteArray.single(): Byte
fun ByteArray.singleOrNull(): Byte?
fun ByteArray.sort(): Unit
fun ByteArray.sortDescending(): Unit
fun ByteArray.sorted(): List<Byte>
fun ByteArray.sortedArray(): ByteArray
fun ByteArray.sortedArrayDescending(): ByteArray
fun ByteArray.sortedDescending(): List<Byte>
fun ByteArray.sum(): Int
fun ByteArray.take(n: Int): List<Byte>
fun ByteArray.takeLast(n: Int): List<Byte>
fun Collection<Byte>.toByteArray(): ByteArray
fun ByteArray.toList(): List<Byte>
fun ByteArray.toSet(): Set<Byte>
fun ByteArray.decodeToString(startIndex: Int = 0, endIndex: Int = this.size, throwOnInvalidSequence: Boolean = false): String
fun String.encodeToByteArray(startIndex: Int = 0, endIndex: Int = this.length, throwOnInvalidSequence: Boolean = false): ByteArray
Range
Types
ClosedRange
interface ClosedRange<T : Comparable<T>>
OpenEndRange
interface OpenEndRange<T : Comparable<T>>
IntProgression
open class IntProgression : PrimitiveIterable<Int>
IntRange
class IntRange : ClosedRange<Int>, OpenEndRange<Int>
LongProgression
open class LongProgression : PrimitiveIterable<Long>
LongRange
class LongRange : ClosedRange<Long>, OpenEndRange<Long>
Extension Properties
val <T : Comparable<T>> ClosedRange<T>.start: T get()
val <T : Comparable<T>> ClosedRange<T>.endInclusive: T get()
val <T : Comparable<T>> OpenEndRange<T>.start: T get()
val <T : Comparable<T>> OpenEndRange<T>.endExclusive: T get()
val IntProgression.first: Int get()
val IntProgression.last: Int get()
val IntProgression.step: Int get()
val LongProgression.first: Long get()
val LongProgression.last: Long get()
val LongProgression.step: Long get()
Extension Functions
operator fun <T : Comparable<T>> ClosedRange<T>.contains(value: T): Boolean
fun <T : Comparable<T>> ClosedRange<T>.isEmpty(): Boolean
operator fun <T : Comparable<T>> OpenEndRange<T>.contains(value: T): Boolean
fun <T : Comparable<T>> OpenEndRange<T>.isEmpty(): Boolean
operator fun <T : Comparable<T>> T.rangeTo(that: T): ClosedRange<T>
operator fun <T : Comparable<T>> T.rangeUntil(that: T): OpenEndRange<T>
fun IntProgression.isEmpty(): Boolean
fun IntProgression.reversed(): IntProgression
infix fun IntProgression.step(step: Int): IntProgression
operator fun IntRange.contains(element: Int?): Boolean
fun IntRange.random(): Int
fun IntRange.randomOrNull(): Int?
infix fun Int.downTo(to: Byte): IntProgression
infix fun Int.downTo(to: Int): IntProgression
infix fun Int.downTo(to: Long): LongProgression
infix fun Int.until(to: Byte): IntRange
infix fun Int.until(to: Int): IntRange
infix fun Int.until(to: Long): LongRange
operator fun Int.rangeTo(that: Int): IntRange
operator fun Int.rangeUntil(that: Int): IntRange
fun LongProgression.isEmpty(): Boolean
fun LongProgression.reversed(): LongProgression
infix fun LongProgression.step(step: Long): LongProgression
operator fun LongRange.contains(element: Long?): Boolean
fun LongRange.random(): Long
fun LongRange.randomOrNull(): Long?
infix fun Long.downTo(to: Byte): LongProgression
infix fun Long.downTo(to: Int): LongProgression
infix fun Long.downTo(to: Long): LongProgression
infix fun Long.until(to: Byte): LongRange
infix fun Long.until(to: Int): LongRange
infix fun Long.until(to: Long): LongRange
operator fun Long.rangeTo(that: Long): LongRange
operator fun Long.rangeUntil(that: Long): LongRange
KDateTime
Types
KDateTimeFormattable
interface KDateTimeFormattable
KPointOfTime
class KPointOfTime : KDateTimeFormattable, Comparable<KPointOfTime>
KDateTimeFormat
class KDateTimeFormat constructor(pattern: String)
KDate
class KDate constructor(year: Int, month: Int, day: Int)
KDuration
class KDuration : KDateTimeFormattable, Comparable<KDuration>
KInstant
class KInstant constructor(timestampMs: Long) : KDateTimeFormattable
KZonedDateTime
class KZonedDateTime constructor(year: Int, month: Int, day: Int, hour: Int, minute: Int, second: Int, millisecond: Int = 0, zoneOffset: KZoneOffset)
KZonedInstant
class KZonedInstant constructor(timestampMs: Long, zoneOffset: KZoneOffset) : KDateTimeFormattable
KZoneOffset
class KZoneOffset constructor(hours: Int, minutes: Int)
Extension Properties
val KZonedInstant.zoneOffset: KZoneOffset get()
val KZoneOffset.Companion.UTC: KZoneOffset get()
val KDuration.Companion.ZERO: KDuration get()
val KZonedDateTime.year: Int get()
val KZonedDateTime.month: Int get()
val KZonedDateTime.day: Int get()
val KZonedDateTime.hour: Int get()
val KZonedDateTime.minute: Int get()
val KZonedDateTime.second: Int get()
val KZonedDateTime.millisecond: Int get()
val KZonedDateTime.zoneOffset: KZoneOffset get()
val KDateTimeFormat.pattern: String get()
var KDateTimeFormat.weekDayNames: List<String> get() set()
val KDateTimeFormat.Companion.ISO8601_DATETIME: KDateTimeFormat get()
val KDateTimeFormat.Companion.FULL: KDateTimeFormat get()
val KDateTimeFormat.Companion.ISO8601_FORMATS: List<KDateTimeFormat> get()
val KDateTimeFormat.Companion.IOS_DATE_FORMATS: List<KDateTimeFormat> get()
val KDateTimeFormat.Companion.WEEKDAY_NAMES: List<String> get()
Extension Functions
operator fun KInstant.plus(duration: KDuration): KInstant
operator fun KInstant.minus(duration: KDuration): KInstant
infix fun KInstant.at(zoneOffset: KZoneOffset): KZonedInstant
fun KInstant.atZoneOffset(zoneOffset: KZoneOffset): KZonedInstant
fun KInstant.atLocalZoneOffset(): KZonedInstant
fun KInstant.Companion.now(): KInstant
fun KInstant.Companion.parseFrom(input: String, formats: List<KDateTimeFormat>): KInstant
fun KDateTimeFormattable.toMilliseconds(): Long
fun KDateTimeFormattable.hourPart(): Int
fun KDateTimeFormattable.minutePart(): Int
fun KDateTimeFormattable.secondPart(): Int
fun KDateTimeFormattable.millisecondPart(): Int
fun KDateTimeFormattable.format(pattern: String): String
fun KPointOfTime.toEpochMilliseconds(): Long
operator fun KPointOfTime.minus(other: KPointOfTime): KDuration
fun KPointOfTime.toIso8601String(): String
fun KPointOfTime.toIso8601StringWithMilliseconds(): String
operator fun KPointOfTime.compareTo(other: KPointOfTime): Int
operator fun KZonedInstant.plus(duration: KDuration): KZonedInstant
operator fun KZonedInstant.minus(duration: KDuration): KZonedInstant
fun KZonedInstant.startOfDay(): KZonedInstant
fun KZonedInstant.dropZoneOffset(): KInstant
fun KZonedInstant.Companion.nowAtLocalZoneOffset(): KZonedInstant
fun KZonedInstant.Companion.nowAtZoneOffset(zoneOffset: KZoneOffset): KZonedInstant
fun KZonedInstant.Companion.parseFrom(input: String, formats: List<KDateTimeFormat>): KZonedInstant
fun KZonedInstant.Companion.parseFromIso8601String(input: String): KZonedInstant
fun KZonedInstant.toKZonedDateTime(): KZonedDateTime
fun KZoneOffset.toMilliseconds(): Long
fun KZoneOffset.toDisplayString(): String
fun KZoneOffset.Companion.parseFrom(string: String): KZoneOffset
fun KZoneOffset.Companion.fromMilliseconds(millis: Long): KZoneOffset
fun KZoneOffset.Companion.local(): KZoneOffset
operator fun KDuration.plus(other: KDuration): KDuration
operator fun KDuration.minus(other: KDuration): KDuration
operator fun KDuration.compareTo(other: KDuration): Int
fun KDuration.toSeconds(): Long
fun KDuration.toMinutes(): Long
fun KDuration.toHours(): Long
fun KDuration.toDays(): Long
fun KDuration.toWeeks(): Long
fun KZonedDateTime.toKZonedInstant(): KZonedInstant
fun KZonedDateTime.startOfDay(): KZonedDateTime
fun KZonedDateTime.copy(year: Int? = null, month: Int? = null, day: Int? = null, hour: Int? = null, minute: Int? = null, second: Int? = null, millisecond: Int? = null, zoneOffset: KZoneOffset? = null): KZonedDateTime
fun KZonedDateTime.format(pattern: String): String
fun KZonedDateTime.toIso8601String(): String
fun KZonedDateTime.toIso8601StringWithMilliseconds(): String
operator fun KZonedDateTime.plus(duration: KDuration): KZonedDateTime
operator fun KZonedDateTime.minus(duration: KDuration): KZonedDateTime
operator fun KZonedDateTime.minus(dateTime: KZonedDateTime): KDuration
fun KDateTimeFormat.format(datetime: KDateTimeFormattable): String
fun KDateTimeFormat.parseToKZonedDateTime(input: String): KZonedDateTime
fun Int.milliseconds(): KDuration
fun Long.milliseconds(): KDuration
fun Int.seconds(): KDuration
fun Long.seconds(): KDuration
fun Int.minutes(): KDuration
fun Int.hours(): KDuration
fun Int.days(): KDuration
fun Int.weeks(): KDuration
fun KInstant.toString(): String
fun KZonedInstant.toString(): String
fun KZonedDateTime.toString(): String
fun KZoneOffset.toString(): String
fun KDuration.toString(): String
Uuid
Types
Uuid
class Uuid
Extension Properties
val Uuid.mostSignificantBits: Long get()
val Uuid.leastSignificantBits: Long get()
val Uuid.bytes: ByteArray get()
val Uuid.variant: Int get()
val Uuid.version: Int get()
Global Functions
fun uuid4(): Uuid
fun uuidFrom(string: String): Uuid
fun uuidOf(bytes: ByteArray): Uuid
fun uuidString(): String
Extension Functions
fun Uuid.toString(): String