Scala Data Types
Every value in Scala has a type. The type tells the compiler what kind of data you are working with and what operations are allowed on it. Scala's type system is one of the most powerful features of the language — it catches mistakes before your program even runs.
Everything Is an Object
In Java, there is a split between "primitive" types like int and boolean, and "object" types like String. Scala eliminates this split. Every value — including numbers and booleans — is an object. This means every value has methods you can call on it.
42.toString // "42"
42.toDouble // 42.0
true.toString // "true"
3.14.toInt // 3
The Scala Type Hierarchy
Any
/ \
AnyVal AnyRef
/ | \ \
Int Double Boolean String
| | | List, Array, etc.
... ... ...
|
Null
|
Nothing
Any is the root type — every Scala value is of type Any. AnyVal covers value types like numbers and booleans. AnyRef covers reference types — objects on the heap, similar to Java's Object. Nothing is a special type with no values — used for functions that never return (like those that always throw an exception).
Numeric Types
Int
Stores whole numbers from about -2.1 billion to +2.1 billion. This is the most commonly used numeric type.
val age: Int = 25
val distance: Int = -300
val population: Int = 1400000000
Long
Stores very large whole numbers. Add an L suffix to signal a Long literal.
val worldPopulation: Long = 8000000000L
val nanoseconds: Long = 1_000_000_000L
Double
Stores decimal numbers with about 15 significant digits of precision. The default type for decimal literals.
val pi: Double = 3.141592653589793
val temperature: Double = -12.5
Float
Stores decimal numbers with about 7 digits of precision. Uses less memory than Double. Add an f suffix.
val weight: Float = 72.5f
Short and Byte
Used in memory-constrained environments. Short holds values from -32768 to 32767. Byte holds -128 to 127.
val small: Short = 1000
val tiny: Byte = 127
Numeric Types Memory Diagram
Type Size Range
────── ─────── ─────────────────────────────
Byte 8 bits -128 to 127
Short 16 bits -32,768 to 32,767
Int 32 bits -2,147,483,648 to 2,147,483,647
Long 64 bits ±9.2 × 10^18
Float 32 bits ~7 decimal digits precision
Double 64 bits ~15 decimal digits precision
Boolean
A Boolean holds exactly one of two values: true or false. Use Booleans for conditions, flags, and yes/no states.
val isLoggedIn: Boolean = true
val hasPermission: Boolean = false
val isMorning: Boolean = 7 < 12 // evaluates to true
Char
A Char holds a single Unicode character, written with single quotes. Not to be confused with a String (which uses double quotes and can hold multiple characters).
val grade: Char = 'A'
val symbol: Char = '₹'
val newline: Char = '\n' // escape sequence
String
A String holds a sequence of characters. Strings use double quotes. In Scala, String is actually java.lang.String under the hood, so all Java String methods work.
val language: String = "Scala"
val greeting: String = "Hello, World!"
val empty: String = ""
// Common String methods
language.length // 5
language.toUpperCase // "SCALA"
language.charAt(0) // 'S'
language.substring(0, 3) // "Sca"
Unit
Unit is Scala's equivalent of void in Java. A function that returns Unit performs an action but produces no meaningful result. println returns Unit.
def sayHi(): Unit =
println("Hi!")
val result = sayHi() // result is ()
println(result) // prints ()
The value of Unit is written as () — an empty pair of parentheses. You almost never use it directly.
Null and None
Scala has null (inherited from Java) but discourages its use. Instead, Scala provides Option to represent values that might be absent. null causes the dreaded NullPointerException when you forget to check for it. Option forces you to handle the absent case explicitly.
// Java-style (avoid this in Scala)
var name: String = null
// Scala-style (preferred)
val name: Option[String] = None
val name2: Option[String] = Some("Priya")
Type Casting
Convert between numeric types using to methods:
val x: Int = 42
val y: Double = x.toDouble // 42.0
val z: Long = x.toLong // 42L
val w: String = x.toString // "42"
val d: Double = 9.99
val i: Int = d.toInt // 9 (truncates, does not round)
Numeric Literals with Underscores
Scala lets you add underscores in numeric literals for readability. The underscores have no effect on the value — they just make large numbers easier to read.
val million: Int = 1_000_000
val billion: Long = 1_000_000_000L
val pi: Double = 3.141_592_653
Type Checking with isInstanceOf
You can check a value's type at runtime using isInstanceOf:
val x: Any = 42
println(x.isInstanceOf[Int]) // true
println(x.isInstanceOf[String]) // false
In practice, you use pattern matching for type checks rather than isInstanceOf — it is safer and more readable. Pattern matching appears in a later topic.
String to Number Conversion
val numStr = "123"
val num: Int = numStr.toInt // 123
val dbl: Double = numStr.toDouble // 123.0
val badStr = "abc"
val bad: Int = badStr.toInt // throws NumberFormatException
Converting an invalid string to a number throws an exception at runtime. Use Try (covered in a later topic) to handle this safely without crashing your program.
Choosing the Right Type
Need to store... Use
───────────────────────── ──────────
Whole numbers (typical) Int
Very large whole numbers Long
Decimal numbers Double
Yes/No flag Boolean
Single character Char
Text String
Optional value Option[T]
Nothing meaningful Unit
Using the right type is not just about correctness — it communicates intent to anyone reading your code and lets the compiler catch mistakes automatically.
