# Basic values in Kotlin

This is a chapter from the book Kotlin Essentials. You can find it on LeanPub or Amazon. It is also available as a course.

Every language needs a convenient way to represent basic kinds of values, like numbers or characters. All languages need to have built-in **types** and **literals**. Types are used to represent certain types of values. Some type examples are `Int`

, `Boolean`

, or `String`

. Literals are built-in notations that are used to create instances. Some literal examples are a string literal, which is text in quotation marks, or an integer literal, which is a bare number.

In this chapter, we’ll learn about the basic Kotlin types and their literals:

- numbers (
`Int`

,`Long`

,`Double`

,`Float`

,`Short`

,`Byte`

), - booleans (
`Boolean`

), - characters (
`Char`

), - strings (
`String`

).

There is also the array primitive type in Kotlin, which will be covered in the chapter *Collections*.

In Kotlin, all values are considered objects (there are no primitive types), so they all have methods, and their types can be used as generic type arguments (this will be covered later). Types that represent numbers, booleans, and characters might be optimized by the Kotlin compiler and used as primitives, but this optimization does not affect Kotlin developers, therefore you don’t need to even think about it.

Let's start discussing the basic types in Kotlin, one by one.

## Numbers

In Kotlin, there is a range of different types that are used to represent numbers. They can be divided into those representing integer numbers (without decimal points) and those representing floating-point numbers (with decimal points). In these groups, the difference is in the number of bits used to represent these numbers, which determines the possible number size and precision.

To represent integer numbers, we use `Int`

, `Long`

, `Byte`

, and `Short`

.

Type | Size (bits) | Min value | Max value |
---|---|---|---|

`Byte` | 8 | -128 | 127 |

`Short` | 16 | -32768 | 32767 |

`Int` | 32 | $-2^{31}$ | $2^{31} - 1$ |

`Long` | 64 | $-2^{63}$ | $2^{63} - 1$ |

To represent floating-point numbers, we use `Float`

and `Double`

.

Type | Size (bits) | Significant bits | Exponent bits | Decimal digits |
---|---|---|---|---|

`Float` | 32 | 24 | 8 | 6-7 |

`Double` | 64 | 53 | 11 | 15-16 |

A plain number without a decimal point is interpreted as an `Int`

. A plain number with a decimal point is interpreted as a `Double`

.

You can create `Long`

by using the `L`

suffix after the number. `Long`

is also used for number literals that are too big for `Int`

.

Similarly, you can create a `Float`

by ending a number with the `F`

or `f`

suffix.

There is no suffix to create `Byte`

or `Short`

types. However, a number explicitly typed as one of these types will create an instance of this type. This also works for `Long`

.

This is not a conversion! Kotlin does not support implicit type conversion, so you cannot use `Byte`

or `Long`

where `Int`

is expected.

If we need to explicitly convert one number to another type, we use explicit conversion functions like `toInt`

or `toLong`

.

### Underscores in numbers

In number literals, we can use the underscore `_`

between digits. This character is ignored, but we sometimes use it to format long numbers for better readability.

### Other numeral systems

To define a number using the hexadecimal numeral system, start it with `0x`

. To define a number using the binary numeral system, start it with `0b`

. The octal numeral system is not supported.

`Number`

and conversion functions

All basic types that represent numbers are a subtype of the `Number`

type.

The `Number`

type specifies transformation functions: from the current number to any other basic type representing a number.

This means that for each basic number you can transform it into a different basic number using the `to{new type}`

function. Such functions are known as *conversion functions*.

### Operations on numbers

Numbers in Kotlin support the basic mathematical operations:

- addition (
`+`

), - subtraction (
`-`

), - multiplication (
`*`

), - division (
`/`

).

Notice, that the correct result of

`1.4 / 2.5`

should be`0.56`

, not`0.5599999999999999`

. This problem will be addressed soon.

Beware that when we divide an `Int`

by an `Int`

, the result is also `Int`

, so the decimal part is lost.

The solution is first to convert an integer into a floating-point representation and then divide it.

There is also a remainder operator^{2} `%`

:

Kotlin also supports operations that modify a read-write variable `var`

:

`+=`

, where`a += b`

is the equivalent of`a = a + b`

,`-=`

, where`a -= b`

is the equivalent of`a = a - b`

,`*=`

, where`a *= b`

is the equivalent of`a = a * b`

,`/=`

, where`a /= b`

is the equivalent of`a = a / b`

,`%=`

, where`a %= b`

is the equivalent of`a = a % b`

,- post-incrementation and pre-incrementation
`++`

, which increment variables value by`1`

, - post-decrementation and pre-decrementation
`--`

, which decrement variables value by`1`

.

### Operations on bits

Kotlin also supports operations on bits using the following methods, which can be called using the infix notation (so, between two values):

`and`

keeps only bits that have`1`

in the same binary positions in both numbers.`or`

keeps only bits that have`1`

in the same binary positions in one or both numbers.`xor`

keeps only bits that have exactly one`1`

in the same binary positions in both numbers.`shl`

shifts the left value left by the right number of bits.`shr`

shifts the left value right by the right number of bits, filling the leftmost bits with copies of the sign bit.`ushr`

shifts the left value right by the right number of bits, filling the leftmost bits with zeros.

`BigDecimal`

and `BigInteger`

All basic types in Kotlin have limited size and precision, which can lead to imprecise or incorrect results in some situations.

This is a standard tradeoff in programming, and in most cases we just need to accept it. However, there are cases where we need to have perfect precision and unlimited number size. On JVM, for unlimited number size we should use `BigInteger`

, which represents a number without a decimal part. For unlimited size and precision, we should use the `BigDecimal`

, which represents a number that has a decimal part. Both can be created using constructors^{1}, factory functions (like `valueOf`

), or a conversion from basic types that represent numbers (`toBigDecimal`

and `toBigInteger`

methods).

`BigDecimal`

and `BigInteger`

also support basic mathematical operators:

On platforms other than Kotlin/JVM, external libraries are needed to represent numbers with unlimited size and precision.

## Booleans

Another basic type is `Boolean`

, which has two possible values: `true`

and `false`

.

We use booleans to express yes/no answers, like:

- Is the user an admin?
- Has the user accepted the cookies policy?
- Are two numbers identical?

In practice, booleans are often a result of some kind of comparison.

### Equality

A `Boolean`

is often a result of equality comparison. In Kotlin, we compare two objects for equality using the double equality sign `==`

. To check if two objects are not equal, we use the non-equality sign `!=`

.

Numbers and all objects that are comparable (i.e., they implement the `Comparable`

interface) can also be compared with `>`

, `<`

, `>=`

, and `<=`

.

### Boolean operations

There are three basic logical operators in Kotlin:

- and
`&&`

, which returns`true`

when the value on both its sides is`true`

; otherwise, it returns`false`

. - or
`||`

, which returns`true`

when the value on either of its sides is`true`

; otherwise, it returns`false`

. - not
`!`

, which turns`true`

into`false`

, and`false`

into`true`

.

Kotlin does not support any kind of automatic conversion to `Boolean`

(or any other type), so logical operators should be used only with objects of type `Boolean`

.

## Characters

To represent a single character, we use the `Char`

type. We specify a character using apostrophes.

Each character is represented as a Unicode number. To find out the Unicode of a character, use the `code`

property.

Kotlin accepts Unicode characters. To describe them by their code, we start with `\u`

, and then we need to use hexadecimal format, just like in Java.

## Strings

Strings are just sequences of characters that form a piece of text. In Kotlin, we create a string using quotation marks `"`

or triple quotation marks `"""`

.

A string wrapped in single quotation marks requires text in a single line. If we want to define a newline character, we need to use a special character `\n`

. This is not the only thing that needs (or might need) a backslash to be expressed in a string.

Escape Sequence | Meaning |
---|---|

`\t` | Tab |

`\b` | Backspace |

`\r` | Carriage return |

`\f` | Form feed |

`\n` | Newline |

`\'` | Single quotation mark |

`\"` | Quotation mark |

`\\` | Backslash |

`\$` | Dollar |

Strings in triple quotation marks can be multiline; in these strings, special characters can be used directly, and forms prefixed by a backslash don’t work.

To better format triple quotation mark strings, we use the `trimIndent`

function, which ignores a constant number of spaces for each line.

String literals may contain template expressions, which are pieces of code that are evaluated and whose results are concatenated into a string. A template expression starts with a dollar sign (`$`

) and consists of either a variable name (like `"text is $text"`

) or an expression in curly braces (like `"1 + 2 = ${1 + 2}"`

).

If you need to use a special character inside a triple quotation mark string, the easiest way is to specify it with a regular string and include it using template syntax.

In Kotlin strings, we use Unicode, so we can also define a Unicode character using a number that starts with `\u`

, and then specifying a Unicode character code in hexadecimal syntax.

You can use `+`

operator to concatenate two strings, so to create a new string that is a combination of two other strings. You can also use this operator to concatenate a string with any other object, which will be converted to a string. The result is always a string.

## Summary

In this chapter, we've learned about the basic Kotlin types and the literals we use to create them:

- Numbers that are represented by types
`Int`

,`Long`

,`Double`

,`Float`

,`Short`

, and`Byte`

are created with bare number values with possible suffixes for type customization. We can define negative numbers or decimal parts. We can also use underscores for nicer number formatting. - Boolean values
`true`

and`false`

are represented by the`Boolean`

type. - Characters, which are represented by the
`Char`

type. We define a character value using single quotation marks. - Strings, which are used to represent text, are represented by the
`String`

type. Each string is just a series of characters. We define strings inside double quotation marks.

So, we have the foundations for using Kotlin. Let's move on to more-complicated control structures that determine how our code behaves.

Constructors will be covered in the chapter *Classes*.

This operator is similar to modulo. Both the remainder and the modulo operations act the same for positive numbers but differently for negative numbers. The result of -5 remainder 4 is -1 because -5 = 4 * (-1) + (-1). The result of -5 modulo 4 is 3 because -5 = 4 * (-2) + 3.