Variables & Data Types
Programs work with data: a student's marks, a train's departure time, the price of a phone. You store that data in variables, named boxes that hold a value. Every value in Kotlin also has a type, which decides what you can do with it.
In this lesson you will create variables with val and var, learn Kotlin's basic types, see how Kotlin works out types for you, and convert between types safely.
val and var
Kotlin has two keywords for variables:
val(from value) creates a read-only variable. Once it has a value, you cannot give it a new one.var(from variable) creates a mutable variable that you can change later.
fun main() {
val name = "Priya"
var balance = 500
println("$name has Rs $balance")
balance = balance + 250
println("$name has Rs $balance")
// name = "Isha" // does not compile: Val cannot be reassigned
}Priya has Rs 500 Priya has Rs 750
Prefer val. Use var only when the value really needs to change, such as a running total or a counter. Code with fewer changing parts is easier to read, and the compiler stops you from changing something by accident.
Name variables in camelCase: start with a lowercase letter and capitalise each new word, as in ticketPrice or totalMarks. Names cannot start with a digit or contain spaces.
Type inference
In the example above, you never wrote a type, yet name is a String and balance is an Int. Kotlin infers (works out) the type from the value. You can also write the type yourself after a colon:
val age: Int = 21
val city: String = "Jaipur"Writing the type is useful when there is no value yet, or when you want a different type from the one Kotlin would choose. Either way, the type is fixed. A var that holds an Int can get a new Int, but never a String.
Basic types
| Type | Holds | Example |
|---|---|---|
Int | whole numbers, about plus or minus 2.1 billion | 42 |
Long | very large whole numbers | 100_000_000_000 or 42L |
Short, Byte | small whole numbers (rarely needed) | val b: Byte = 10 |
Double | decimal numbers, about 15-16 digits of precision | 99.5 |
Float | decimal numbers, about 6-7 digits | 99.5f |
Boolean | true or false | true |
Char | one character, in single quotes | 'A' |
String | text, in double quotes | "Kochi" |
You can check what Kotlin inferred by printing a value's class name:
fun main() {
val runs = 87
val starsInGalaxy = 100_000_000_000
val average = 45.5
val ratio = 0.75f
val passed = true
val grade = 'A'
val city = "Lucknow"
println(runs::class.simpleName)
println(starsInGalaxy::class.simpleName)
println(average::class.simpleName)
println(ratio::class.simpleName)
println(passed::class.simpleName)
println(grade::class.simpleName)
println(city::class.simpleName)
}Int Long Double Float Boolean Char String
Some rules to remember:
- A whole number is an
Intif it fits; if it is too big forInt, it becomes aLong. AddLto force aLong:42L. - A number with a decimal point is a
Double. Addffor aFloat. - Underscores make long numbers readable:
1_00_000is one lakh,1_000_000is one million. The compiler ignores them. - Kotlin also has unsigned types such as
UIntandULongfor values that are never negative (val count: UInt = 42u). You will rarely need them as a beginner.
Limits and overflow
Each number type has a smallest and largest value. If an Int calculation goes past the largest value, it overflows and wraps around to a large negative number, without any error.
fun main() {
println(Int.MAX_VALUE)
println(Long.MAX_VALUE)
val max = Int.MAX_VALUE
println(max + 1)
println(max.toLong() + 1)
}2147483647 9223372036854775807 -2147483648 2147483648
Use Long for values that can grow very large, such as a country's population in a calculation, file sizes in bytes or amounts in paise.
Converting between types
Kotlin never converts number types silently. An Int is not automatically turned into a Long or Double, even though that would be safe. You call a conversion function instead: toInt(), toLong(), toDouble(), toString() and friends.
fun main() {
val marks = 437
val total = 500
val percent = marks.toDouble() / total * 100
println(percent)
println(9.99.toInt())
println((-9.99).toInt())
val price = "1299".toInt()
println(price + 1)
println(price.toString() + "1")
}87.4 9 -9 1300 12991
Notice three things. First, marks.toDouble() turns the division into decimal division; without it, 437 / 500 would be whole-number division and give 0. Second, toInt() on a Double simply cuts off the decimal part, so 9.99 becomes 9, not 10. Third, "1299".toInt() turns text into a number, while toString() does the opposite, which is why the last line joins the texts "1299" and "1".
Writing val big: Long = marks does not compile, because marks is an Int. Write marks.toLong().
Constants and late initialisation
For a value that is known when the program is compiled and never changes, use const val at the top level of a file. By convention, constants use UPPER_SNAKE_CASE.
A val can also be declared first and given its value later, as long as it is assigned exactly once before use:
const val GST_RATE = 18
fun main() {
val isMember = true
val bill: Int
if (isMember) {
bill = 900
} else {
bill = 1000
}
println("Bill: Rs $bill, GST: $GST_RATE%")
}Bill: Rs 900, GST: 18%
The compiler checks that bill gets a value on every path before it is printed. You will see a shorter way to write this with an if expression in if & when Expressions.
Common mistakes
- Using
vareverywhere. Start withvaland change it tovaronly when the compiler tells you the value must change. - Expecting automatic conversion.
val d: Double = 5does not compile. Write5.0or5.toDouble(). - Whole-number division by accident.
7 / 2is3. Convert one side toDoubleto get3.5. - Rounding with
toInt(). It truncates. UseroundToInt()fromkotlin.math(see Operators & Math) when you want rounding. - Ignoring overflow.
Intsilently wraps past 2,147,483,647. UseLongfor big values.
Key points
valis read-only,varcan change; preferval.- Kotlin infers types from values, but each variable's type is fixed once chosen.
- Main types:
Int,Long,Double,Float,Boolean,Char,String. - Number types never convert silently; use
toInt(),toLong(),toDouble()andtoString(). Intoverflows without an error;Longholds much bigger values.const valdeclares compile-time constants at the top level.
Exercise
Rohan's monthly salary is Rs 38,500. Store it in a val, and store his savings rate of 15 percent in another val. Calculate his yearly savings as a Double and print it. Then store the yearly savings in a var, add a festival bonus of Rs 10,000 to it, and print the new value as a whole number using toInt().
Show solution
fun main() {
val salary = 38_500
val savingsRate = 15
var yearlySavings = salary * 12 * savingsRate / 100.0
println(yearlySavings)
yearlySavings = yearlySavings + 10_000
println(yearlySavings.toInt())
}69300.0 79300
Dividing by 100.0 makes the result a Double. yearlySavings is a var because it changes when the bonus is added.
Quick Quiz
1. What happens if you try to assign a new value to a val?
A val is read-only; the compiler rejects any second assignment.
2. What type does Kotlin infer for val x = 3.0?
A number with a decimal point is a Double unless you add f.
3. What does 9.99.toInt() return?
toInt() cuts off the decimal part; it does not round.
4. Which line compiles?
5L is a Long literal. Kotlin never converts Int to Long or Double automatically.
Learn Kotlin with a mentor
Free lessons get you started. Our Programming & Software Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
