Tutorials

Scala Tutorial: Using Options, Some, and None

Key Takeaways

  • Option[T] represents zero or one value: Some(value) means present, and None means absent.
  • Some(value) constructs an option; it does not extract a value from one.
  • Use getOrElse, pattern matching, or fold to handle both cases. Use map and flatMap to keep working with optional results.
  • Options make absence explicit, but they aren't an automatic safety guarantee: .get can throw, and Some(null) is possible.

Scala Option is a type for a value that might be missing. Instead of returning a string or null, you return Option[String]: either Some("Joe") or None, so callers can see that absence is part of the result.

The examples below use Scala 3 with brace syntax. You can enter the short snippets in the Scala REPL, an interactive environment that evaluates Scala code. The Person example is also a complete program.

What Is a Scala Option?

Option[T] describes an optional value of type T. Its two cases are Some, which contains a value, and None, which contains no value.

// Scala — enter these declarations in the REPL.
val firstName: Option[String] = Some("Joe")
val missingName: Option[String] = None

More precisely, Option is an algebraic data type: a type described by a fixed set of alternatives. The standard library implements it as a sealed abstract class with Some and None as its alternatives. It has collection-like operations, but its purpose is to represent optionality, not an arbitrary number of elements. See Scala's introduction to algebraic data types for the underlying idea.

Why Use Options Instead of null?

A method returning Option[String] advertises that its result may be absent. That information travels with the value through method calls instead of depending on a comment or an undocumented convention. Scala's functional error-handling guide uses Option for exactly this kind of optional result.

The compiler distinguishes Option[String] from String, so you can't use an optional string directly wherever a string is required. When you choose pattern matching, the compiler can also warn about missing cases because Option is sealed.

Scala Option Basic Example: Person and Pattern Matching

This program preserves the distinction between a person with a first name and a person without one:

// Scala — save as OptionExample.scala in your Scala project.
case class Person(firstName: Option[String])

object OptionExample {
  def printName(name: Option[String]): Unit = {
    name match {
      case Some(n) => println(s"Hello, my name is $n")
      case None    => println("No name provided")
    }
  }

  def main(args: Array[String]): Unit = {
    val person = Person(Some("Joe"))
    val person2 = Person(None)

    printName(person.firstName)
    printName(person2.firstName)
  }
}

Output:

Hello, my name is Joe
No name provided

In case Some(n), the pattern binds the contained value to n. The None branch handles absence separately. This is useful when the two cases need different behavior, rather than just different values.

If the declaration is unfamiliar, start with our guide to Scala case classes.

Getting the Option Value Safely

Constructing and extracting are different operations. Writing Some("Joe") creates an option. Writing case Some(n) in a match extracts its contents within that branch. Neither operation changes an existing option.

Use getOrElse When a Default Is Appropriate

getOrElse returns the contained value when present and the supplied fallback otherwise. It doesn't mutate the option or remove its contents.

// Scala — standalone REPL example.
def printNameOrDefault(name: Option[String]): Unit = {
  val n = name.getOrElse("No name provided")
  println(n)
}

printNameOrDefault(Some("Joe")) // Joe
printNameOrDefault(None)        // No name provided

The fallback expression is evaluated only when the option is empty. Its parameter is by-name, meaning evaluation is delayed until the method needs it.

// Scala — standalone REPL example.
def defaultName(): String = {
  println("Computing default")
  "Guest"
}

val known: Option[String] = Some("Joe")
val unknown: Option[String] = None

known.getOrElse(defaultName())   // Returns Joe; prints nothing.
unknown.getOrElse(defaultName()) // Prints Computing default; returns Guest.

Pass the computation directly if you want that delayed behavior. Computing it into an ordinary val before the call performs the work earlier, regardless of whether the option needs it.

Use orElse to Preserve an Optional Result

A default is appropriate when replacing absence makes sense—for example, displaying “Guest” in a greeting. If absence still matters to the next operation, keep an Option instead. orElse returns the original nonempty option or evaluates an alternative option when the original is empty.

// Scala — standalone REPL example.
val preferred: Option[String] = None
val backup: Option[String] = Some("Joe")

val selected: Option[String] = preferred.orElse(backup) // Some(Joe)
val stillMissing: Option[String] = preferred.orElse(None) // None

Use fold to Return a Result for Either Case

fold takes a result for the empty case, followed by a function for the present case. Here, both branches produce a String, just as an explicit match could.

// Scala — standalone REPL example.
def greeting(name: Option[String]): String = {
  name.fold("No name provided")(n => s"Hello, my name is $n")
}

println(greeting(Some("Joe"))) // Hello, my name is Joe
println(greeting(None))        // No name provided

Use foreach When Nothing Should Happen for None

foreach runs its body only when the option is nonempty. It returns Unit, so use it for an action such as printing, not for producing a transformed optional value.

// Scala — standalone REPL example.
def printNameIfPresent(name: Option[String]): Unit = {
  name.foreach { n => println(s"Hello, my name is: $n") }
}

printNameIfPresent(Some("Joe")) // Hello, my name is: Joe
printNameIfPresent(None)        // No output.

Composing Scala Options with map and flatMap

You don't always need to extract a value. Often, you want to transform it or pass it to another operation that also returns an option. The Option API reference documents these composition methods.

Start with a Lookup That Returns Option

A Scala map's get method returns Some(value) when the key exists and None otherwise. This is different from Option.get, which attempts to extract an already-optional value.

// Scala — enter this setup in the REPL.
case class Contact(name: String, email: Option[String])

val contacts: Map[Int, Contact] = Map(
  1 -> Contact("Joe", Some("joe@example.com")),
  2 -> Contact("Sam", None)
)

def findContact(id: Int): Option[Contact] = contacts.get(id)

The return type tells callers that the contact might not exist. Separately, Contact.email tells them that an existing contact might not have an email address.

Use map for a Transformation

map applies a function to the contained value and wraps its result in Some. On None, it skips the function and returns None.

// Scala — continue after the lookup setup above.
val foundName: Option[String] = findContact(1).map(contact => contact.name)
val missingName: Option[String] = findContact(99).map(contact => contact.name)

println(foundName)   // Some(Joe)
println(missingName) // None

The contact => contact.name expression is an anonymous function. Our guide to Scala lambdas and higher-order functions explains that syntax.

Use flatMap When the Next Result Is Already Optional

Because email is already an Option[String], mapping to it creates a nested Option[Option[String]]. flatMap instead returns the function's optional result directly, avoiding the extra wrapper.

// Scala — continue after the lookup setup above.
val nested: Option[Option[String]] = findContact(1).map(_.email)

def emailFor(id: Int): Option[String] = {
  findContact(id).flatMap(contact => contact.email)
}

println(nested)       // Some(Some(joe@example.com))
println(emailFor(1))  // Some(joe@example.com)
println(emailFor(2))  // None: contact exists, but email is absent.
println(emailFor(99)) // None: contact doesn't exist.

Both kinds of absence reach the caller without an explicit conditional. Notice the trade-off: the final None doesn't distinguish a missing contact from a missing email. If callers need that distinction, model those outcomes separately.

filter is another collection-like operation: it keeps a present value when a condition passes and returns None otherwise. These operations let you work with optional values without treating Option as a general-purpose collection.

Checking Whether an Option Is None

isDefined reports whether an option is Some; isEmpty reports whether it is None. Both are parameterless methods, written without parentheses.

// Scala — standalone REPL example.
val some: Option[String] = Some("some string")
val none: Option[String] = None

println(some.isDefined) // true
println(none.isDefined) // false
println(some.isEmpty)   // false
println(none.isEmpty)   // true

Use these tests when you actually need a Boolean. If your next step is to extract or transform the value, prefer pattern matching, getOrElse, map, or flatMap rather than checking first and then calling .get.

Common Mistakes

  • Using .get as the normal extraction method. On None, it throws NoSuchElementException. Choose a fallback, handle both cases, or preserve the option instead.
  • Assuming Some means non-null. Some(null) is nonempty. At a boundary that can supply null, the Option factory converts null to None and a non-null value to Some(value).
  • Replacing absence too early. Keep optional results optional until you reach the place that should choose a default.

This counterexample deliberately ends with an exception:

// Scala — demonstration of unsafe assumptions.
println(Some(null).isDefined) // true
println(Option(null))         // None

Option.empty[String].get     // Throws NoSuchElementException.

FAQ

What is Option in Scala?

Option[T] represents an optional value of type T: either Some(value) or None. It makes possible absence explicit in a field, parameter, or return type.

What is the difference between Some and None in Scala?

Some(value) contains a value, while None represents absence. Calling Some(value) constructs an option; it doesn't extract a value from an existing option.

How do you get a value from an Option in Scala?

Use getOrElse to supply a fallback, or use pattern matching or fold to handle both cases. Avoid calling .get for normal absence handling because it throws NoSuchElementException on None.

What is the difference between map and flatMap on Option?

map wraps the function's result in Some. flatMap expects the function to return an Option and returns that result directly, avoiding nested options; both skip the function on None.

Can Some contain null?

Yes. Some(null) is nonempty, whereas Option(null) returns None. Use Option(value) when converting a potentially null value into an optional result.

Further Reading

Written by Sam Erickson

Software engineer. I write every article on StackChief myself. More about me