Option type
A.k.a Maybe (Haskell), Optional (Java 8)
Models the absence of a value
β In the sense of a possibility for a value to be absent
β β unit: used in the case where there is never a value
Defined as a union with 2 cases :
type Option<'Value> =
| None // Case without data β when value is missing
| Some of 'Value // Case with data β when value is presentCommon use cases:
Modeling an optional field
Turning a partial operation into a total operation
Modeling an optional field
type Civility = Mr | Mrs
type User = { Name: string; Civility: Civility option }
let joey = { Name = "Joey"; Civility = Some Mr }
let guest = { Name = "Guest"; Civility = None }β Make it explicit that Name is mandatory and Civility optional
β Warning: this design does not prevent Name = null here (BCL limit)
Partial to total operation
An operation is partial when no output value is possible for certain inputs.
The operation can become total by wrapping the result in an
option,Nonebeing used when the operation gives no output.
Example 1: inverse of a number
Function
Operation
Signature
n = 0.5
n = 0.0
inverse
Partial
float -> float
2.0
infinity β
tryInverse
Total
float -> float option
Some 2.0
None π
Example 2: find an element in a collection
Partial operation:
find predicateβ π₯ when item not foundTotal operation:
tryFind predicateβNoneorSome item
Benefits π
Explicit, honest regarding partial operation
No special value:
null,infinityNo exception
Forces calling code to handle all cases:
Some valueβ output value givenNone .....β output value missing
Control flow
How to test for the presence of the value (of type 'T) in the option?
β Do not use
if option.IsSome then ... option.Valuepatternβ Do pattern match the option
β Do use
Option.xxxfunctions
Control flow with pattern matching
Example:
Control flow with Option.xxx helpers
Option.xxx helpersMapping of the inner value (of type 'T) if present:
β map f option with f total operation 'T -> 'U
β bind f option with f partial operation 'T -> 'U option
Keep value if present and if conditions are met:
β filter predicate option with predicate: 'T -> bool called only if value present
Exercise
Implement map, bind and filter with pattern matching
Example
Advantages
Makes business logic more readable
No
if hasValue then / elseHighlight the happy path
Handle corner cases at the end
π‘ Alternative syntax more light: ad-hoc computation expressions π
Option: comparison with other types
Option: comparison with other typesOptionvsListOptionvsNullableOptionvsnull
Option vs List
Option vs ListConceptually similar
β Option β List of 0 or 1 items
β See Option.toList function: 't option -> 't list (None -> [], Some x -> [x])
π‘ Option & List modules: many functions with the same name
β contains, count, exist, filter, fold, forall, map
β A List can have more than 1 element
β Type Option models absence of value better than type List
Option vs Nullable
Option vs NullableSystem.Nullable<'T> β Option<'T> but more limited
β Does not work for reference types
β Lacks monadic behavior i.e.
mapandbindfunctionsβ Lacks built-in pattern matching
Some x | Noneβ In Fβ―, no magic as in Cβ― with the
nullkeyword
Example:
π Cβ― uses Nullable whereas Fβ― uses only Option. However, Nullable can be required with some libraries, for instance to deal with nullable columns in a database.
Option vs null
Option vs nullDue to the interop with the BCL, Fβ― has to deal with null objects in some cases.
π Good practice: isolate these cases and wrap them in an Option type.
Nullable reference types
Fβ― 9 introduces nullable reference types: a type-safe way to deal with reference types that can have null as a valid value.
This feature must be activated:
Adds
<Nullable>enable</Nullable>in your.fsprojPasses
--checknulls+options todotnet fsi- seeFSharp.FSIExtraInteractiveParameterssettings in vscode
Then, | null needs to be added to the type annotation to indicate that null as a valid value. It's really similar to nullable reference types: Fβ― string | null is equivalent to Cβ― string?, with the usual tradeoff for explicitness over terseness/magic.
π More details regarding this feature and how Fβ― handles nullity (e.g. with AllowNullLiteral attribute): Nullable Reference Types in F# 9.
Last updated
Was this helpful?