# Option type

Last updated

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`).

## Contents

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 (`Maybe (Maybe A)``Maybe A`), while nullable types do not (`String??` = `String?`).

## Theoretical aspects

In type theory, it may be written as: ${\displaystyle A^{?}=A+1}$. This expresses the fact that for a given set of values in ${\displaystyle A}$, an option type adds exactly one additional value (the empty value) to the set of valid values for ${\displaystyle A}$. 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. [1]

In the Curry–Howard correspondence, option types are related to the annihilation law for ∨: x∨1=1.[ how? ]

An option type can also be seen as a collection containing either one or zero elements.[ original research? ]

The option type is also a monad where: [2]

`return=Just-- Wraps the value into a maybeNothing>>=f=Nothing-- Fails if the previous monad fails(Justx)>>=f=fx-- Succeeds when both monads succeed`

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

## Names and definitions

In different programming languages, the option type has various names and definitions.

• In Agda, it is named `Maybe` with variants `nothing` and `just a`.
• In C++17 it is defined as the template class `std::optional<T>`, `optional()` can be used to create an empty option. (Might break monad laws due to the heavy overloading of constructors.)
• In C#, it is defined as `Nullable<T>` but is generally written as `T?`. (Breaks monad laws.)
• In Coq, it is defined as `Inductiveoption(A:Type):Type:=|Some:A->optionA|None:optionA.`.
• In Elm, it is named `Maybe`, and defined as `typeMaybea=Justa|Nothing`. [4]
• In Haskell, it is named `Maybe`, and defined as `dataMaybea=Nothing|Justa`.
• In Idris, it is defined as `dataMaybe a =Nothing|Just a`.
• In Java, since version 8, it is defined as parameterized final class `Optional<T>`. (Breaks monad laws (map is implemented incorrectly).)
• In Julia, it is named `Nullable{T}`. (However, this has been deprecated. [5] )
• In OCaml, it is defined as `type'aoption=None|Someof'a`.
• In Perl 6, this is the default, but you can add a `:D` "smiley" to opt into a non option type. (Breaks monad laws (does not support nesting.))
• In Rust, it is defined as `enumOption<T>{None,Some(T)}`.
• In Scala, it is defined as `sealedabstractclassOption[+A]`, a type extended by `finalcaseclassSome[+A](value:A)` and `caseobjectNone`.
• In Standard ML, it is defined as `datatype'aoption=NONE|SOMEof'a`.
• In Swift, it is defined as `enumOptional<T>{casenone,some(T)}` but is generally written as `T?`. [6]

## Examples

Ada does not implement option-types directly, however it provides discriminated types which can be used to parameterize a record. To implement a 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.TypeElement_Typeisprivate;PackageOptional_Typeis-- When the discriminant, Has_Element, is true there is an element field,-- when it is false, there are no fields (hence the null keyword).TypeOptional(Has_Element: Boolean)isrecordcaseHas_ElementiswhenFalse=>Null;whenTrue=>Element:Element_Type;endcase;end record;endOptional_Type;`

### Scala

Scala implements `Option` as a parameterized type, so a variable can be an `Option`, accessed as follows: [7]

`objectMain{// This function uses pattern matching to deconstruct `Option`sdefcomputeV1(opt:Option[Int]):String=optmatch{caseSome(x)=>s"The value is: \$x"caseNone=>"No value"}// This function uses the built-in `fold` methoddefcomputeV2(opt:Option[Int]):String=opt.fold("No value")(x=>s"The value is: \$x")defmain(args:Array[String]):Unit={// Define variables that are `Option`s of type `Int`valfull=Some(42)valempty:Option[Int]=None// computeV1(full) -> The value is: 42println(s"computeV1(full) -> \${computeV1(full)}")// computeV1(empty) -> No valueprintln(s"computeV1(empty) -> \${computeV1(empty)}")// computeV2(full) -> The value is: 42println(s"computeV2(full) -> \${computeV2(full)}")// computeV2(empty) -> No valueprintln(s"computeV2(empty) -> \${computeV2(empty)}")}}`

Two main ways to use an `Option` value exist. The first, not the best, is the pattern matching, as in the first example. The second, the best practice is a monadic approach, as in the second example. In this way, a program is safe, as it can generate no exception or error (e.g., by trying to obtain the value of an `Option` variable that is equal to `None`). Thus, it essentially works as a type-safe alternative to the null value.

### OCaml

OCaml implements `Option` as a parameterized variant type. `Option`s are constructed and deconstructed as follows:

`(* This function uses pattern matching to deconstruct `option`s *)letcompute_v1=function|Somex->"The value is: "^string_of_intx|None->"No value"(* This function uses the built-in `fold` function *)letcompute_v2=Option.fold~none:"No value"~some:(funx->"The value is: "^string_of_intx)let()=(* Define variables that are `option`s of type `int` *)letfull=Some42inletempty=Nonein(* compute_v1 full -> The value is: 42 *)print_endline("compute_v1 full -> "^compute_v1full);(* compute_v1 empty -> No value *)print_endline("compute_v1 empty -> "^compute_v1empty);(* compute_v2 full -> The value is: 42 *)print_endline("compute_v2 full -> "^compute_v2full);(* compute_v2 empty -> No value *)print_endline("compute_v2 empty -> "^compute_v2empty)`

### F#

`// This function uses pattern matching to deconstruct `option`sletcompute_v1=function|Somex->sprintf"The value is: %d"x|None->"No value"// This function uses the built-in `fold` functionletcompute_v2=Option.fold(fun_x->sprintf"The value is: %d"x)"No value"// Define variables that are `option`s of type `int`letfull=Some42letempty=None// compute_v1 full -> The value is: 42compute_v1full|>printfn"compute_v1 full -> %s"// compute_v1 empty -> No valuecompute_v1empty|>printfn"compute_v1 empty -> %s"// compute_v2 full -> The value is: 42compute_v2full|>printfn"compute_v2 full -> %s"// compute_v2 empty -> No valuecompute_v2empty|>printfn"compute_v2 empty -> %s"`

`-- This function uses pattern matching to deconstruct `Maybe`scomputeV1::MaybeInt->StringcomputeV1(Justx)="The value is: "++showxcomputeV1Nothing="No value"-- This function uses the built-in `foldl` functioncomputeV2::MaybeInt->StringcomputeV2=foldl(\_x->"The value is: "++showx)"No value"main::IO()main=do-- Define variables that are `Maybe`s of type `Int`letfull=Just42letempty=Nothing-- computeV1 full -> The value is: 42putStrLn\$"computeV1 full -> "++computeV1full-- computeV1 full -> No valueputStrLn\$"computeV1 empty -> "++computeV1empty-- computeV2 full -> The value is: 42putStrLn\$"computeV2 full -> "++computeV2full-- computeV2 full -> No valueputStrLn\$"computeV2 empty -> "++computeV2empty`

### Swift

`// This function uses a `switch` statement to deconstruct `Optional`sfunccomputeV1(_opt:Int?)->String{switchopt{case.some(letx):return"The value is: \(x)"case.none:return"No value"}}// This function uses optional binding to deconstruct `Optional`sfunccomputeV2(_opt:Int?)->String{ifletx=opt{return"The value is: \(x)"}else{return"No value"}}// Define variables that are `Optional`s of type `Int`letfull:Int?=42letempty:Int?=nil// computeV1(full) -> The value is: 42print("computeV1(full) -> \(computeV1(full))")// computeV1(empty) -> No valueprint("computeV1(empty) -> \(computeV1(empty))")// computeV2(full) -> The value is: 42print("computeV2(full) -> \(computeV2(full))")// computeV2(empty) -> No valueprint("computeV2(empty) -> \(computeV2(empty))")`

### Rust

`// This function uses a `match` expression to deconstruct `Option`sfncompute_v1(opt: &Option<i32>)-> String{matchopt{Some(x)=>format!("The value is: {}",x),None=>"No value".to_owned(),}}// This function uses an `if let` expression to deconstruct `Option`sfncompute_v2(opt: &Option<i32>)-> String{ifletSome(x)=opt{format!("The value is: {}",x)}else{"No value".to_owned()}}// This function uses the built-in `map_or` methodfncompute_v3(opt: &Option<i32>)-> String{opt.map_or("No value".to_owned(),|x|format!("The value is: {}",x))}fnmain(){// Define variables that are `Option`s of type `i32`letfull=Some(42);letempty: Option<i32>=None;// compute_v1(&full) -> The value is: 42println!("compute_v1(&full) -> {}",compute_v1(&full));// compute_v1(&empty) -> No valueprintln!("compute_v1(&empty) -> {}",compute_v1(&empty));// compute_v2(&full) -> The value is: 42println!("compute_v2(&full) -> {}",compute_v2(&full));// compute_v2(&empty) -> No valueprintln!("compute_v2(&empty) -> {}",compute_v2(&empty));// compute_v3(&full) -> The value is: 42println!("compute_v3(&full) -> {}",compute_v3(&full));// compute_v3(&empty) -> No valueprintln!("compute_v3(&empty) -> {}",compute_v3(&empty))}`

### Nim

`importoptions# This proc uses the built-in `isSome` and `get` procs to deconstruct `Option`sproc compute(opt:Option[int]):string=ifopt.isSome:"The Value is: "&\$opt.getelse:"No value"# Define variables that are `Optional`s of type `Int`letfull=some(42)empty=none(int)# compute(full) -> The Value is: 42echo"compute(full) -> ",compute(full)# compute(empty) -> No valueecho"compute(empty) -> ",compute(empty)`

## Related Research Articles

In computer programming, lazy initialization is the tactic of delaying the creation of an object, the calculation of a value, or some other expensive process until the first time it is needed. It is a kind of lazy evaluation that refers specifically to the instantiation of objects or other resources.

In object-oriented programming, the iterator pattern is a design pattern in which an iterator is used to traverse a container and access the container's elements. The iterator pattern decouples algorithms from containers; in some cases, algorithms are necessarily container-specific and thus cannot be decoupled.

F# is a functional-first, general purpose, strongly typed, multi-paradigm programming language that encompasses functional, imperative, and object-oriented programming methods. F# is most often used as a cross-platform Common Language Infrastructure (CLI) language on .NET Core, but it can also generate JavaScript and graphics processing unit (GPU) code.

In mathematics and computer science, a higher-order function is a function that does at least one of the following:

In computer science, a tagged union, also called a variant, variant record, choice type, discriminated union, disjoint union, sum type or coproduct, is a data structure used to hold a value that could take on several different, but fixed, types. Only one of the types can be in use at any one time, and a tag field explicitly indicates which one is in use. It can be thought of as a type that has several "cases", each of which should be handled correctly when that type is manipulated. This is critical in defining recursive datatypes, in which some component of a value may have the same type as the value itself, for example in defining a type for representing trees, where it is necessary to distinguish multi-node subtrees and leafs. Like ordinary unions, tagged unions can save storage by overlapping storage areas for each type, since only one is in use at a time.

In functional programming, a monad is an abstraction that allows structuring programs generically. Supporting languages may use monads to abstract away boilerplate code needed by the program logic. Monads achieve this by providing their own data type, which represents a specific form of computation, along with one procedure to wrap values of any basic type within the monad and another to compose functions that output monadic values.

Foreach loop is a control flow statement for traversing items in a collection. Foreach is usually used in place of a standard for loop statement. Unlike other for loop constructs, however, foreach loops usually maintain no explicit counter: they essentially say "do this to everything in this set", rather than "do this x times". This avoids potential off-by-one errors and makes code simpler to read. In object-oriented languages an iterator, even if implicit, is often used as the means of traversal.

In class-based object-oriented programming, a constructor is a special type of subroutine called to create an object. It prepares the new object for use, often accepting arguments that the constructor uses to set required member variables.

The syntax of Java refers to the set of rules defining how a Java program is written and interpreted.

In computer programming, an entry point is where the first instructions of a program are executed, and where the program has access to command line arguments.

Exception handling syntax is the set of keywords and/or structures provided by a computer programming language to allow exception handling, which separates the handling of errors that arise during a program's operation from its ordinary processes. Syntax for exception handling varies between programming languages, partly to cover semantic differences but largely to fit into each language's overall syntactic structure. Some languages do not call the relevant concept "exception handling"; others may not have direct facilities for it, but can still provide means to implement it.

In computer programming, a semipredicate problem occurs when a subroutine intended to return a useful value can fail, but the signalling of failure uses an otherwise valid return value. The problem is that the caller of the subroutine cannot tell what the result means in this case.

Nullable types are a feature of some programming languages which allow the value to be set to the special value NULL instead of the usual possible values of the data type. In statically typed languages, a nullable type is an option type, while in dynamically typed languages, equivalent behavior is provided by having a single null value.

In computer programming, an anonymous function is a function definition that is not bound to an identifier. Anonymous functions are often arguments being passed to higher-order functions, or used for constructing the result of a higher-order function that needs to return a function. If the function is only used once, or a limited number of times, an anonymous function may be syntactically lighter than using a named function. Anonymous functions are ubiquitous in functional programming languages and other languages with first-class functions, where they fulfil the same role for the function type as literals do for other data types.

Generics are a facility of generic programming that were added to the Java programming language in 2004 within version J2SE 5.0. They were designed to extend Java's type system to allow "a type or method to operate on objects of various types while providing compile-time type safety". The aspect compile-time type safety was not fully achieved, since it was shown in 2016 that it is not guaranteed in all cases.

The null coalescing operator is a binary operator that is part of the syntax for a basic conditional expression in several programming languages, including C#, PowerShell as of version 7.0.0, Perl as of version 5.10, Swift, and PHP 7.0.0. While its behavior differs between implementations, the null coalescing operator generally returns the result of its left-most operand if it exists and is not null, and otherwise returns the right-most operand. This behavior allows a default value to be defined for cases where a more specific value is not available.

Elm is a domain-specific programming language for declaratively creating web browser-based graphical user interfaces. Elm is purely functional, and is developed with emphasis on usability, performance, and robustness. It advertises "no runtime exceptions in practice", made possible by the Elm compiler's static type checking.

Kotlin is a cross-platform, statically typed, general-purpose programming language with type inference. Kotlin is designed to interoperate fully with Java, and the JVM version of Kotlin's standard library depends on the Java Class Library, but type inference allows its syntax to be more concise. Kotlin mainly targets the JVM, but also compiles to JavaScript or native code, e.g. for native iOS apps sharing business logic with Android apps. Language development costs are borne by JetBrains, while the Kotlin Foundation protects the Kotlin trademark.

Ur also called Ur/Web is a Free and Open source functional programming language specific for web development, created by Adam Chlipala at the Massachusetts Institute of Technology that from a single program produces server code, browser client code and SQL code specific for the chosen database backend.

## References

1. Milewski, Bartosz (2015-01-13). "Simple Algebraic Data Types". Bartosz Milewski's Programming Cafe. Sum types. "We could have encoded Maybe as: data Maybe a = Either () a". Archived from the original on 2019-08-18. Retrieved 2019-08-18.