Imagine you’re writing universal domain logic for your program. All I/O is provided via an interface (like UI, persistent storage, networking, etc.), you don’t have to think about it, and you almost don’t care about the platform, on which you run. Your program is fairly simple, only a few straightforward tasks. This chapter describes all essentials you need to write it. The foundational basics that you can build upon: data, processing primitives, and functions to reuse code.
Data
At the core of any program, lies the data. The sole purpose is to often receive and transform, sometimes create, but always output the data. A program that doesn’t output anything is useless. Take away variables (or functions that act as variables) and there’s nothing to process. In this section, cornerstone data representations are discussed: primitive data types, variables, collections, ranges, text, optionals, and function types.
Note: Custom data types (structs, classes) are showcased later, in the Abstractions chapter. They help a lot and make your program much easier to reason about, but you don’t absolutely need them. You can get away by structuring your data using collections, Map a.k.a. Dictionary a.k.a. Associative Array in particular. This has been demonstrated by Lua scripting language, for example.
Primitive types
Variables and symbolic constants:
val constant = "immutable"
var x = "mutable"
x = "mutable variable"
Boolean
val flag: Boolean = true
Numbers
Kotlin’s type system is designed around the Java Virtual Machine (JVM) and thus inherits its limitations. Notoriously, Java/JVM doesn’t support unsigned integers, so Kotlin uses a workaround to add the support. This is fine in most cases, but can be problematic for Java or iOS interop (KMP). Use at your own risk. Kotlin Docs
val b: Byte = 0x7F
val s: Short = 32_767
val i: Int = -2_147_483_648
val l: Long = 1L
// JVM supports only signed integer types.
// Kotlin offers their unsigned counterparts as custom types layered on top.
// Technically, these are not primitive types, so be careful.
val ub: UByte = 0xFFu
val us: UShort = 65_535U
val ui: UInt = 4_294_967_295u
val ul: ULong = 1UL
var d: Double = 3.14
d = .01
d = 1_001e1_000
d = 1.1E10
var f: Float = 3.14f
f = 1F
Text
var c: Char = 'c'
c = '\n'
c = '\u005C'
var text: String = "Text"
text = """
Multiline
text
"""
Anything
A value of any type can be stored in a variable of the common supertype Any. Everything inherits from Any. However, the type is so general that it’s not very useful aside from passing indetermined things around.
What happens is: A more specific type is boxed and then unboxed when cast back from Any. (See below, in Optionals.) This has performance cost.
var a: Any = true
a = "some other type"
Note: A special dynamic type is available for JavaScript targets. It opts out from type checking. Kotlin Docs