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.
Post History
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 a returns value a "wrapped" in a .NET Sy...
Answer
#2: Post edited
- [`box`][1] and [`unbox`][1] are **operators** documented in the [F# Core API Reference][2]; it tersely states that **they box / unbox (respectively) a strongly typed value**.
+ `box a` returns value `a` wrapped in a .NET [`System.Object`][3] instance- + `unbox<a_type> a` will try to unwrap value `a` and cast it into an `a_type` or throw an exception otherwise
- For completeness' sake, there is also a [`tryUnbox`][4] operator, that can be called the same way as `unbox`, but it returns the boxed value wrapped in an [`Option`][5].
- ### Example use cases
- #### 1. Type detection during runtime
- The F# for Fun and Profit article [Built-in .NET types][6]<sup><b>1</b></sup> has an [entire section dedicated to `box` and `unbox`][7] which ends with the following example:
- <sup>\[1]: That is, types of the [Common Language Infrastructure][8] (CLI).</sup>
- > 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#?][9] 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][10] would set the
- > required parameter to `null` even though `Int` cannot be `null`. This
- > was very confusing, and, to make matters worse, we were not able to
- > make the required parameter a `Nullable<Int>` with [WebAPI][10].
- >
- > **The Solution** - Box is the solution! From our searching, by boxing the `int` we could check if it is `null` even though it's not nullable
- > (confusing). But what does the box function do? According to [[the
- > docs][1]], the `box` function 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][11] article of the C# Programming Guide], the answer is
- >
- > > **Boxing is the process of converting a [value type][12] to the type `object`** or to any interface type implemented by this value type.
- > When the [common language runtime][13] (CLR) boxes a [value type][12],
- > **it wraps the value inside a [`System.Object`][3] instance and stores it on the managed heap**. Unboxing extracts the [value type][12] 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.Object`][3]
- > and therefore we can check if the object is `null`. Then we have to
- > unbox it back to an `Int` after the `null` check.
- [1]: https://fsharp.github.io/fsharp-core-docs/reference/fsharp-core-operators.html#box
- [2]: https://fsharp.github.io/fsharp-core-docs/
- [3]: https://learn.microsoft.com/en-us/dotnet/api/system.object
- [4]: https://fsharp.github.io/fsharp-core-docs/reference/fsharp-core-operators.html#tryUnbox
- [5]: https://fsharp.github.io/fsharp-core-docs/reference/fsharp-core-optionmodule.html
- [6]: https://fsharpforfunandprofit.com/posts/cli-types/
- [7]: https://fsharpforfunandprofit.com/posts/cli-types/#boxing-and-unboxing
- [8]: https://en.wikipedia.org/wiki/Common_Language_Infrastructure
- [9]: http://www.functionaladam.com/2016/04/what-is-box-in-f.html
- [10]: https://learn.microsoft.com/en-us/aspnet/core/web-api/
- [11]: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/boxing-and-unboxing
- [12]: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-types
- [13]: https://learn.microsoft.com/en-us/dotnet/standard/clr
- [`box`][1] and [`unbox`][1] are **operators** documented in the [F# Core API Reference][2]; it tersely states that **they box / unbox (respectively) a strongly typed value**.
- + `box a` returns value `a` "wrapped" in a .NET [`System.Object`][3] instance
- "wrapped" here simply means that `a` is upcast to `System.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> a` will try to unwrap value `a` and cast it into an `a_type` or throw an exception otherwise
- For completeness' sake, there is also a [`tryUnbox`][4] operator, that can be called the same way as `unbox`, but it returns the boxed value wrapped in an [`Option`][5].
- ### Example use cases
- #### 1. Type detection during runtime
- The F# for Fun and Profit article [Built-in .NET types][6]<sup><b>1</b></sup> has an [entire section dedicated to `box` and `unbox`][7] which ends with the following example:
- <sup>\[1]: That is, types of the [Common Language Infrastructure][8] (CLI).</sup>
- > 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#?][9] 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][10] would set the
- > required parameter to `null` even though `Int` cannot be `null`. This
- > was very confusing, and, to make matters worse, we were not able to
- > make the required parameter a `Nullable<Int>` with [WebAPI][10].
- >
- > **The Solution** - Box is the solution! From our searching, by boxing the `int` we could check if it is `null` even though it's not nullable
- > (confusing). But what does the box function do? According to [[the
- > docs][1]], the `box` function 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][11] article of the C# Programming Guide], the answer is
- >
- > > **Boxing is the process of converting a [value type][12] to the type `object`** or to any interface type implemented by this value type.
- > When the [common language runtime][13] (CLR) boxes a [value type][12],
- > **it wraps the value inside a [`System.Object`][3] instance and stores it on the managed heap**. Unboxing extracts the [value type][12] 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.Object`][3]
- > and therefore we can check if the object is `null`. Then we have to
- > unbox it back to an `Int` after the `null` check.
- [1]: https://fsharp.github.io/fsharp-core-docs/reference/fsharp-core-operators.html#box
- [2]: https://fsharp.github.io/fsharp-core-docs/
- [3]: https://learn.microsoft.com/en-us/dotnet/api/system.object
- [4]: https://fsharp.github.io/fsharp-core-docs/reference/fsharp-core-operators.html#tryUnbox
- [5]: https://fsharp.github.io/fsharp-core-docs/reference/fsharp-core-optionmodule.html
- [6]: https://fsharpforfunandprofit.com/posts/cli-types/
- [7]: https://fsharpforfunandprofit.com/posts/cli-types/#boxing-and-unboxing
- [8]: https://en.wikipedia.org/wiki/Common_Language_Infrastructure
- [9]: http://www.functionaladam.com/2016/04/what-is-box-in-f.html
- [10]: https://learn.microsoft.com/en-us/aspnet/core/web-api/
- [11]: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/boxing-and-unboxing
- [12]: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-types
- [13]: https://learn.microsoft.com/en-us/dotnet/standard/clr
#1: Initial revision
[`box`][1] and [`unbox`][1] are **operators** documented in the [F# Core API Reference][2]; it tersely states that **they box / unbox (respectively) a strongly typed value**. + `box a` returns value `a` wrapped in a .NET [`System.Object`][3] instance + `unbox<a_type> a` will try to unwrap value `a` and cast it into an `a_type` or throw an exception otherwise For completeness' sake, there is also a [`tryUnbox`][4] operator, that can be called the same way as `unbox`, but it returns the boxed value wrapped in an [`Option`][5]. ### Example use cases #### 1. Type detection during runtime The F# for Fun and Profit article [Built-in .NET types][6]<sup><b>1</b></sup> has an [entire section dedicated to `box` and `unbox`][7] which ends with the following example: <sup>\[1]: That is, types of the [Common Language Infrastructure][8] (CLI).</sup> > 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#?][9] 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][10] would set the > required parameter to `null` even though `Int` cannot be `null`. This > was very confusing, and, to make matters worse, we were not able to > make the required parameter a `Nullable<Int>` with [WebAPI][10]. > > **The Solution** - Box is the solution! From our searching, by boxing the `int` we could check if it is `null` even though it's not nullable > (confusing). But what does the box function do? According to [[the > docs][1]], the `box` function 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][11] article of the C# Programming Guide], the answer is > > > **Boxing is the process of converting a [value type][12] to the type `object`** or to any interface type implemented by this value type. > When the [common language runtime][13] (CLR) boxes a [value type][12], > **it wraps the value inside a [`System.Object`][3] instance and stores it on the managed heap**. Unboxing extracts the [value type][12] 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.Object`][3] > and therefore we can check if the object is `null`. Then we have to > unbox it back to an `Int` after the `null` check. [1]: https://fsharp.github.io/fsharp-core-docs/reference/fsharp-core-operators.html#box [2]: https://fsharp.github.io/fsharp-core-docs/ [3]: https://learn.microsoft.com/en-us/dotnet/api/system.object [4]: https://fsharp.github.io/fsharp-core-docs/reference/fsharp-core-operators.html#tryUnbox [5]: https://fsharp.github.io/fsharp-core-docs/reference/fsharp-core-optionmodule.html [6]: https://fsharpforfunandprofit.com/posts/cli-types/ [7]: https://fsharpforfunandprofit.com/posts/cli-types/#boxing-and-unboxing [8]: https://en.wikipedia.org/wiki/Common_Language_Infrastructure [9]: http://www.functionaladam.com/2016/04/what-is-box-in-f.html [10]: https://learn.microsoft.com/en-us/aspnet/core/web-api/ [11]: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/boxing-and-unboxing [12]: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/value-types [13]: https://learn.microsoft.com/en-us/dotnet/standard/clr