Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
What does F#'s box keyword do and where is it documented?
The Null Values article in the F# Language Reference show an example that uses it, but it does not explain what it does exactly.
You can use the following code to check if an arbitrary value is
null.match box value with | null -> printf "The value is null." | _ -> printf "The value is not null."
I went through the entire PDF version of the language reference, but there is not trace of it ever being introduced.
1 answer
box and unbox are operators documented in the F# Core API Reference; it tersely states that they box / unbox (respectively) a strongly typed value.
-
box areturns valuea"wrapped" in a .NETSystem.Objectinstance"wrapped" here simply means that
ais upcast toSystem.Object:type Lofa = | A | B match A with | :? Lofa -> A //=> error FS0016 match (box A) with | :? Lofa -> A //ok match (A :> obj) | :? Lofa -> A //ok match (A :> System.Object) | :? Lofa -> A //ok -
unbox<a_type> awill try to unwrap valueaand cast it into ana_typeor throw an exception otherwise
For completeness' sake, there is also a tryUnbox operator, that can be called the same way as unbox, but it returns the boxed value wrapped in an Option.
Example use cases
1. Type detection during runtime
The F# for Fun and Profit article Built-in .NET types1 has an entire section dedicated to box and unbox which ends with the following example:
[1]: That is, types of the Common Language Infrastructure (CLI).
Let’s say that you want to have a function that matches based on the type of the parameter, using the
:?operator:let detectType v = match v with | :? int -> printfn "this is an int" | _ -> printfn "something else"Unfortunately, this code will fail to compile, with the following error:
// error FS0008: This runtime coercion or type test // from type 'a to int involves an indeterminate type // based on information prior to this program point. // Runtime type tests are not allowed on some types. // Further type annotations are needed.The message tells you the problem:
runtime type tests are not allowed on some types.The answer is to “box” the value which forces it into a reference type, and then you can type check it:
let detectTypeBoxed v = match box v with // used "box v" | :? int -> printfn "this is an int" | _ -> printfn "something else" //test detectTypeBoxed 1 detectTypeBoxed 3.14
2. Interoperability with non-F# .NET projects
The Functional Adam post What is box in F#? nicely complements the example in the question:
The Problem - The variable was in
Int, it was required, and if it was not provided, our application was supposed to return an error code. When the parameter was not provided, WebAPI would set the required parameter tonulleven thoughIntcannot benull. This was very confusing, and, to make matters worse, we were not able to make the required parameter aNullable<Int>with WebAPI.The Solution - Box is the solution! From our searching, by boxing the
intwe could check if it isnulleven though it's not nullable (confusing). But what does the box function do? According to [the docs], theboxfunction in F# "boxes a strongly typed value". Ok... Thanks documentation.That's not all very helpful, but with further digging in [the Boxing and Unboxing article of the C# Programming Guide], the answer is
Boxing is the process of converting a value type to the type
objector to any interface type implemented by this value type. When the common language runtime (CLR) boxes a value type, it wraps the value inside aSystem.Objectinstance and stores it on the managed heap. Unboxing extracts the value type from the object. Boxing is implicit; unboxing is explicit. The concept of boxing and unboxing underlies the C# unified view of the type system in which a value of any type can be treated as an object.So, boxing a value wraps the value type inside a
System.Objectand therefore we can check if the object isnull. Then we have to unbox it back to anIntafter thenullcheck.

0 comment threads