Scala Basic Data Types
Work with basic data types in Scala — Scala for Python Developers.
Focus: work with basic data types in scala
You already know how to store a number, a string, or a boolean in Python—it’s second nature. But when you start writing Scala, the same simple task suddenly feels foreign: val x: Int = 42 looks like a declaration from another planet, and you’re not sure why Double and Float both exist. The pain is real: you can write Python-style Scala and get away with it—until a type mismatch crashes your build or a runtime ClassCastException surprises you in production. This lesson bridges that gap by teaching you to work with basic data types in Scala the idiomatic way, so you stop translating Python and start thinking in Scala.
The problem this lesson solves
Python’s dynamic typing means you rarely think about the underlying type of a variable. x = 5 just works, and x = "five" also works. In Scala, which is statically typed and runs on the JVM, the story is different. Your code must declare—or let the compiler infer—a concrete type for every value. Using the wrong type can lead to compilation errors, runtime exceptions, or subtle bugs that only appear under load.
For example, consider this Python snippet:
# Python: dynamic and forgiving
def add(a, b):
return a + b
print(add(1, 2)) # 3
print(add("1", "2")) # "12"
In Scala, the analogous function fails to compile without a type annotation, and even with one, Int + Int and String + String are completely different operations. If you carry Python’s “any type goes” mindset into Scala, you’ll hit friction early. The problem this lesson solves is knowing which basic types Scala offers, how to declare them, and how to convert between them safely—so you can write code that compiles cleanly and runs predictably.
Core concept / mental model
Think of Scala’s type system as a contract between you and the compiler. Every variable has a type that is known at compile time, which means the compiler catches many mistakes before your code ever runs. This is the opposite of Python’s duck typing, where checks happen at runtime.
A useful mental model: imagine each Scala basic type is a labeled box. The label tells the compiler exactly what can go inside. An Int box holds 32-bit integers from -2,147,483,648 to 2,147,483,647. A Long box holds 64-bit integers. A Double box holds 64-bit floating-point numbers. When you write val age: Int = 30, you’re saying “this box is labeled Int, and it contains 30.” If you try to put a string inside that box, the compiler refuses—it’s like trying to fit a watermelon into a shoebox.
Here’s a table of Scala’s basic types and their Python equivalents, so you can map what you already know:
| Scala type | Description | Python equivalent |
|---|---|---|
Int |
32-bit signed integer | int (though Python ints are arbitrary precision) |
Long |
64-bit signed integer | int (for big numbers) |
Double |
64-bit floating-point | float |
Float |
32-bit floating-point | float (less precise) |
Char |
16-bit Unicode character | str (single character) |
String |
Sequence of Char |
str |
Boolean |
true or false |
bool |
Unit |
No value (akin to None in return) |
None (when a function returns nothing) |
Notice that Scala’s String is not a basic type in the same sense as Int—it’s a class—but for everyday use, you treat it like one. Also note the precision limits: a Python int can grow arbitrarily large, but a Scala Int overflows silently past its bounds. This is a critical difference you’ll revisit in the troubleshooting section.
How it works step by step
Declaring variables with val and var
In Scala, you declare an immutable value with val and a mutable variable with var. This is your first step to working with types correctly. Use val by default—immutability prevents bugs and aligns with functional programming principles.
val name: String = "Ada"
val age: Int = 37
var counter: Int = 0 // mutable only when necessary
counter = counter + 1 // OK because counter is a var
// name = "Grace" // Compilation error: reassignment to val
Using type inference
You don’t always need to write the type; the compiler can infer it from the right-hand side. This feels closer to Python’s simplicity. However, for clarity in public APIs, many Scala developers annotate the type explicitly.
val city = "London" // Inferred as String
val population = 9_000_000 // Inferred as Int (underscores are allowed for readability)
val pi = 3.14159 // Inferred as Double
Numbers: Int, Long, Float, Double
Choose the smallest type that fits your data. For whole numbers, Int is the default but overflows at 2^31-1. For larger ranges, use Long. For floating-point, Double is the default and usually preferred over Float for precision.
val small = 123 // Int
val big = 12345678901L // Long (note the L suffix)
val ratio: Float = 0.5f // Float (note the f suffix)
val precise = 0.123456789 // Double (default for decimals)
Characters and strings
Char holds a single Unicode character, while String holds a sequence. Scala strings are immutable and support many methods similar to Python’s str.
val letter: Char = 'A'
val greeting: String = "Hello"
val multiLine = """Line 1
Line 2"""
println(greeting.length) // 5
println(greeting.toUpperCase) // HELLO
Booleans and unit
Boolean is simply true or false. The Unit type represents the absence of a meaningful value—similar to None in Python when a function returns nothing. Functions that return Unit are like Python functions that return None.
val isReady: Boolean = true
val result: Unit = println("Done") // println returns Unit
Type conversions
Scala does not implicitly convert between numeric types. You must call conversion methods like .toInt, .toDouble, .toString, etc. This is a deliberate design choice to avoid silent precision loss.
val numString = "42"
val numInt = numString.toInt
val numDouble = numInt.toDouble
val numLong = numInt.toLong
println(numInt + 1) // 43
println(numDouble) // 42.0
Hands-on walkthrough
Let’s put it together with a practical exercise. We’ll write a small Scala program that reads user input, processes it, and prints a result—mimicking a common Python script but in Scala syntax.
Create a file BasicTypes.scala with the following code:
import scala.io.StdIn
object BasicTypes {
def main(args: Array[String]): Unit = {
println("Enter your age:")
val input = StdIn.readLine()
val age = input.toInt
val ageNextYear = age + 1
val isAdult = age >= 18
val message = s"In one year, you'll be $ageNextYear. Adult: $isAdult"
println(message)
println(s"Double your age: ${age * 2}")
}
}
Run it with scala BasicTypes.scala (or via your build tool). Expected output when you enter 30:
Enter your age:
30
In one year, you'll be 31. Adult: true
Double your age: 60
Now, try a variant that handles potential input errors gracefully. Scala’s Try is like Python’s try/except but returns a value:
import scala.io.StdIn
import scala.util.Try
object SafeInput {
def main(args: Array[String]): Unit = {
println("Enter a float:")
val input = StdIn.readLine()
val number = Try(input.toDouble).getOrElse(0.0)
println(s"You entered: $number")
}
}
If you type 3.14, it prints 3.14. If you type abc, it prints 0.0 instead of crashing—a nice pattern to remember.
Compare options / when to choose what
When working with numbers, you often choose between Int and Long, or Float and Double. Here’s a comparison table to guide your decision:
| Type | Range / Precision | Use when | Python equivalent |
|---|---|---|---|
Int |
32-bit: -2^31 to 2^31-1 | Default for small integers | int (but unbounded) |
Long |
64-bit: -2^63 to 2^63-1 | Counters, timestamps, large numbers | int |
Float |
32-bit, ~7 decimal digits | Graphics, memory-sensitive arrays | float (but default double) |
Double |
64-bit, ~15 decimal digits | Most floating-point math | float |
For strings, Scala’s String is complete and supports many Python-like methods, but for complex text processing you might reach for libraries (like StringOps or regex). For booleans, there’s no alternative—just stick with Boolean.
A key decision is whether to use val or var. Favor val unless you have a specific need to mutate state. In Python, there’s no such distinction, but in Scala it affects correctness and concurrency safety.
Troubleshooting & edge cases
Integer overflow
Unlike Python, Scala’s Int silently overflows. For example:
val max = Int.MaxValue
val overflow = max + 1
println(overflow) // prints -2147483648 (overflowed!)
In Python, you’d never see this because ints grow. In Scala, always consider using Long or BigInt for values near the limits.
Type mismatch errors
The compiler enforces types. If you try:
val x: Int = "hello" // Compilation error: type mismatch
You’ll get an error. This is a feature—it catches bugs early.
String to number conversions fail
When converting a string to a number, an invalid format throws NumberFormatException. Python’s int("abc") raises ValueError; Scala throws a different exception type but crashes similarly. Use Try or pattern matching to handle it gracefully.
Precision loss
Converting Double to Int truncates the decimal part, not rounds.
val d = 3.999
val i = d.toInt
println(i) // 3, not 4
Be explicit if you need rounding (math.round).
Char vs String
Remember that single quotes denote Char, double quotes denote String. Mixing them causes errors. Python only has strings, so this is a new gotcha.
What you learned & what's next
You’ve learned the core idea of working with basic data types in Scala: the type system acts as a safety net, different numeric types have different ranges, and conversions are explicit. You completed a hands-on exercise that reads user input, converts it to an Int, and performs arithmetic. You also saw how to handle conversion errors with Try. This directly meets the learning objectives of explaining the core idea and completing a practical exercise.
Next, you’ll dive into collections—you’ll learn how to work with lists, sets, and maps in Scala, and how they compare to Python’s data structures. That will build on this foundation, so make sure you’re comfortable with the basic types before moving on.
Practice recap
To solidify what you learned, write a short Scala program that asks for the user's birth year, converts it to an Int, calculates their age, and prints it as a Long. Use Try to handle invalid input gracefully. Then try mixing Double and Int by computing body mass index (BMI) with height and weight inputs, converting as needed.
Common mistakes
- Trying to add an
Intand aStringwith+— in Scala,+is overloaded for string concatenation, so1 + "2"compiles to"12"silently, while in Python it raises a TypeError. Always convert explicitly. - Forgetting that
Intoverflows silently; Python ints grow unbounded, butInt.MaxValue + 1becomes negative. UseLongorBigIntfor large numbers. - Assuming implicit type conversion exists: in Python,
1 + 2.0gives3.0, but in Scala you must call.toDoubleor.toIntexplicitly. Otherwise your code won’t compile. - Using single quotes for a string literal: in Scala,
'a'is aChar, not aString. Double quotes are required for strings, which trips up Python devs used to only one string type.
Variations
- Using
BigIntandBigDecimalfor arbitrary precision—closer to Python’s unboundedintanddecimalmodule. - Leveraging pattern matching with types:
x match { case i: Int => ... }to handle different types dynamically, similar to isinstance checks in Python. - Using
Optionfor nullable values instead ofnullor Python’sNone—you’ll see this in collections and I/O later in the track.
Real-world use cases
- Parsing JSON payloads in a REST API where fields can be integers or floats, requiring explicit conversion to avoid precision loss.
- Handling user input in a command-line tool, like a Scala CLI that reads a numeric ID and converts it to an
IntorLongfor processing. - Writing data validation logic in a Spark job that reads CSV strings and converts them to typed columns (
toInt,toDouble) for aggregation.
Key takeaways
- Scala’s basic types are
Int,Long,Float,Double,Char,String,Boolean, andUnit—each with a specific range or precision. - Prefer
valovervarfor immutability, just like Python’s convention of not reassigning when not necessary. - Type inference works, but explicit annotations improve readability—especially for public APIs.
- Numeric conversions are explicit in Scala: use
.toInt,.toDouble, etc., to avoid silent precision loss. - Handle conversion errors with
Tryor pattern matching instead of letting exceptions crash your program. - Watch out for integer overflow with
Intand useLongorBigIntfor large numbers.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.