In programming languages (especially functional programming languages) and type theory, an option type or maybe type is a polymorphic type that represents encapsulation of an optional value; e.g., it is used as the return type of functions which may or may not return a meaningful value when they are applied. It consists of a constructor which either is empty (often named None or Nothing), or which encapsulates the original data type A (often written Just A or Some A).

A distinct, but related concept outside of functional programming, which is popular in object-oriented programming, is called nullable types (often expressed as A?). The core difference between option types and nullable types is that option types support nesting (e.g. Maybe (Maybe String) ≠ Maybe String), while nullable types do not (e.g. String?? = String?).

Theoretical aspects In type theory, it may be written as: . This expresses the fact that for a given set of values in , an option type adds exactly one additional value (the empty value) to the set of valid values for . This is reflected in programming by the fact that in languages having tagged unions, option types can be expressed as the tagged union of the encapsulated type plus a unit type. An option type is a particular case of a tagged union, where the Nothing is taken as (nullary constructor for a) singleton type. Tagged unions can generally be implemented by a combination of union types and record types using occurrence typing.https://arxiv.org/pdf/2111.03354 p. 8

The option type is also a monad where:

return = Just -- Wraps the value into a maybe

Nothing >>= f = Nothing -- Fails if the previous monad fails (Just x) >>= f = f x -- Succeeds when both monads succeed

The monadic nature of the option type is useful for efficiently tracking failure and errors.

Examples

Ada Ada does not implement option-types directly, however it provides discriminated types which can be used to parameterize a record. To implement an Option type, a Boolean type is used as the discriminant; the following example provides a generic to create an option type from any non-limited constrained type: generic -- Any constrained & non-limited type. type Element_Type is private; package Optional_Type is -- When the discriminant, Has_Element, is true there is an element field, -- when it is false, there are no fields (hence the null keyword). type Optional (Has_Element : Boolean) is record case Has_Element is when False => Null; when True => Element : Element_Type; end case; end record; end Optional_Type;

Example usage: package Optional_Integers is new Optional_Type (Element_Type => Integer); Foo : Optional_Integers.Optional := (Has_Element => True, Element => 5); Bar : Optional_Integers.Optional := (Has_Element => False);

Agda

In Agda, the option type is named with variants and .

ATS

In ATS, the option type is defined as

datatype option_t0ype_bool_type (a: t@ype+, bool) = | Some(a, true) of a | None(a, false) stadef option = option_t0ype_bool_type typedef Option(a: t@ype) = [b:bool] option(a, b)

#include "share/atspre_staload.hats"

fn show_value (opt: Option int): string = case+ opt of | None() => "No value" | Some(s) => tostring_int s

implement main0 (): void = let val full = Some 42 and empty = None in println!("show_value full → ", show_value full); println!("show_value empty → ", show_value empty); end

show_value full → 42 show_value empty → No value

C++ Since C++17, the option type is defined in the standard library as . import std;

using std::nullopt; using std::optional;

constexpr optional<double> divide(double x, double y) noexcept { if (y != 0.0) { return x / y;

return nullopt; }

void readDivisionResults(int x, int y) { optional<double> result = divide(x, y); if (result) { std::println("The quotient of x: {} and y: {} is {}.", x, y, result.value()); } else { std::println("The quotient of x: {} and y: {} is undefined!", x, y);

int main(int argc, char* argv[]) { readDivisionResults(1, 5); readDivisionResults(8, 0);

In C++23, support for monadic operations for is available.

Elm

In Elm, the option type is defined as .

F#

In F#, the option type is defined as .

let showValue = Option.fold (fun _ x -> sprintf "The value is: %d" x) "No value"

let full = Some 42 let empty = None

showValue full |> printfn "showValue full -> %s" showValue empty |> printfn "showValue empty -> %s"

showValue full -> The value is: 42 showValue empty -> No value

Haskell

In Haskell, the option type is defined as .

showValue :: Maybe Int -> String showValue = foldl (\_ x -> "The value is: " ++ show x) "No value"

main :: IO () main = do let full = Just 42 let empty = Nothing

putStrLn $ "showValue full -> " ++ showValue full putStrLn $ "showValue empty -> " ++ showValue empty

showValue full -> The value is: 42 showValue empty -> No value

Idris

In Idris, the option type is defined as .

showValue : Maybe Int -> String showValue = foldl (\_, x => "The value is " ++ show x) "No value"

main : IO () main = do let full = Just 42 let empty = Nothing

putStrLn $ "showValue full -> " ++ showValue full putStrLn $ "showValue empty -> " ++ showValue empty

showValue full -> The value is: 42 showValue empty -> No value

Java

In Java, the option type is defined the standard library by the class.

import java.util.Optional;

public class OptionExample { static String showValue(Optional<Integer> opt) { return opt.map(x -> String.format("The value is: %d", x)).orElse("No value");

public static void main(String[] args) { Optional<Integer> full = Optional.of(42); Optional<Integer> empty = Optional.empty();

System.out.printf("showValue(full): %s\n", showValue(full)); System.out.printf("showValue(empty): %s\n", showValue(empty));

showValue full -> The value is: 42 showValue empty -> No value

Nim

import std/options

proc showValue(opt: Option[int]): string = opt.map(proc (x: int): string = "The value is: " & $x).get("No value")

let full = some(42) empty = none(int)

echo "showValue(full) -> ", showValue(full) echo "showValue(empty) -> ", showValue(empty)

showValue(full) -> The Value is: 42 showValue(empty) -> No value

OCaml

In OCaml, the option type is defined as .

let show_value = Option.fold ~none:"No value" ~some:(fun x -> "The value is: " ^ string_of_int x)

let () = let full = Some 42 in let empty = None in

print_endline ("show_value full -> " ^ show_value full); print_endline ("show_value empty -> " ^ show_value empty)

show_value full -> The value is: 42 show_value empty -> No value

Rocq

In Rocq, the option type is defined as .

Rust

In Rust, the option type is defined as .

fn show_value(opt: Option<i32>) -> String { opt.map_or("No value".to_owned(), |x: i32| format!("The value is: {}", x)) }

fn main() { let full: Option<i32> = Some(42); let empty: Option<i32> = None;

println!("show_value(full) -> {}", show_value(full)); println!("show_value(empty) -> {}", show_value(empty)); }

show_value(full) -> The value is: 42 show_value(empty) -> No value

Scala

In Scala, the option type is defined as , a type extended by and .

object Main: def showValue(opt: Option[Int]): String = opt.fold("No value")(x => s"The value is: $x")

def main(args: Array[String]): Unit = val full = Some(42) val empty = None

println(s"showValue(full) -> ${showValue(full)}") println(s"showValue(empty) -> ${showValue(empty)}")

showValue(full) -> The value is: 42 showValue(empty) -> No value

Standard ML

In Standard ML, the option type is defined as .

Swift

In Swift, the option type is defined as but is generally written as .

func showValue(_ opt: Int?) -> String { return opt.map { "The value is: \($0)" } ?? "No value" }

let full = 42 let empty: Int? = nil

print("showValue(full) -> \(showValue(full))") print("showValue(empty) -> \(showValue(empty))")

showValue(full) -> The value is: 42 showValue(empty) -> No value

Zig

In Zig, add ? before the type name like ?i32 to make it an optional type.

Payload n can be captured in an if or while statement, such as , and an else clause is evaluated if it is null.

const std = @import("std");

fn showValue(gpa: std.mem.Allocator, opt: ?i32) ![]u8 { return if (opt) |n| std.fmt.allocPrint(gpa, "The value is: {}", .{n}) else gpa.dupe(u8, "No value"); }

pub fn main(init: std.process.Init) !void { // Prepare the standard output stream. var buffer: u8 = undefined; var writer = std.Io.File.stdout().writer(init.io, &buffer);

// Perform our example. const full = 42; const empty = null;

const full_msg = try showValue(init.gpa, full); defer init.gpa.free(full_msg); try writer.interface.print("showValue(init.gpa, full) -> {s}\n", .{full_msg});

const empty_msg = try showValue(init.gpa, empty); defer init.gpa.free(empty_msg); try writer.interface.print("showValue(init.gpa, empty) -> {s}\n", .{empty_msg});

try writer.interface.flush(); }

showValue(init.gpa, full) -> The value is: 42 showValue(init.gpa, empty) -> No value

See also Result type Tagged union Nullable type Null object pattern Exception handling Pattern matching

References