When interacting with C# libraries, I find myself wanting C#'s null coalescing operator both for Nullable
structs and reference types.
Is it possible to approximate this in F# with a single overloaded operator that inlines the appropriate if
case?
The nullish coalescing operator ( ?? ) is a logical operator that returns its right-hand side operand when its left-hand side operand is null or undefined , and otherwise returns its left-hand side operand.
operator is known as Null-coalescing operator. It will return the value of its left-hand operand if it is not null. If it is null, then it will evaluate the right-hand operand and returns its result. Or if the left-hand operand evaluates to non-null, then it does not evaluate its right-hand operand.
JavaScript made sure this can be handled with its nullish operator also known as the Null Coalescing Operator, which was added to the language with ECMAScript 2020. With it, you can either return a value or assign it to some other value, depending on a boolean expression.
The null-coalescing operator ?? returns the value of its left-hand operand if it isn't null ; otherwise, it evaluates the right-hand operand and returns its result.
Yes, using some minor hackery found in this SO answer "Overload operator in F#".
At compiled time the correct overload for an usage of either ('a Nullable, 'a) ->'a
or ('a when 'a:null, 'a) -> 'a
for a single operator can be inlined. Even ('a option, 'a) -> 'a
can be thrown in for more flexibility.
To provide closer behavior to c# operator, I've made default parameter 'a Lazy
so that it's source isn't called unless the original value is null
.
Example:
let value = Something.PossiblyNullReturned() |?? lazy new SameType()
Implementation:
NullCoalesce.fs [Gist]:
//https://gist.github.com/jbtule/8477768#file-nullcoalesce-fs type NullCoalesce = static member Coalesce(a: 'a option, b: 'a Lazy) = match a with | Some a -> a | _ -> b.Value static member Coalesce(a: 'a Nullable, b: 'a Lazy) = if a.HasValue then a.Value else b.Value static member Coalesce(a: 'a when 'a:null, b: 'a Lazy) = match a with | null -> b.Value | _ -> a let inline nullCoalesceHelper< ^t, ^a, ^b, ^c when (^t or ^a) : (static member Coalesce : ^a * ^b -> ^c)> a b = // calling the statically inferred member ((^t or ^a) : (static member Coalesce : ^a * ^b -> ^c) (a, b)) let inline (|??) a b = nullCoalesceHelper<NullCoalesce, _, _, _> a b
Alternatively I made a library that utilizes this technique as well as computation expression for dealing with Null/Option/Nullables, called FSharp.Interop.NullOptAble
It uses the operator |?->
instead.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With