Scala Basic Data Types

Work with basic data types in Scala — Scala for Python Developers.

Focus: work with basic data types in scala

Sponsored

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 Int and a String with + — in Scala, + is overloaded for string concatenation, so 1 + "2" compiles to "12" silently, while in Python it raises a TypeError. Always convert explicitly.
  • Forgetting that Int overflows silently; Python ints grow unbounded, but Int.MaxValue + 1 becomes negative. Use Long or BigInt for large numbers.
  • Assuming implicit type conversion exists: in Python, 1 + 2.0 gives 3.0, but in Scala you must call .toDouble or .toInt explicitly. Otherwise your code won’t compile.
  • Using single quotes for a string literal: in Scala, 'a' is a Char, not a String. Double quotes are required for strings, which trips up Python devs used to only one string type.

Variations

  1. Using BigInt and BigDecimal for arbitrary precision—closer to Python’s unbounded int and decimal module.
  2. Leveraging pattern matching with types: x match { case i: Int => ... } to handle different types dynamically, similar to isinstance checks in Python.
  3. Using Option for nullable values instead of null or Python’s None—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 Int or Long for 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, and Unit—each with a specific range or precision.
  • Prefer val over var for 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 Try or pattern matching instead of letting exceptions crash your program.
  • Watch out for integer overflow with Int and use Long or BigInt for large numbers.

Sponsored

Sponsored

Discussion

Questions, corrections, and tips help everyone reading this page.

0 comments

Add a comment

Shown publicly with your comment.

Be constructive · max 4,000 characters

No comments yet — start the thread.

Related tutorials, quizzes, and articles for this topic.