Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

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

71%
+3 −0
Q&A What does F#'s `box` keyword do and where is it documented?

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

posted 11mo ago by toraritte‭  ·  edited 11mo ago by toraritte‭

Answer
#2: Post edited by user avatar toraritte‭ · 2024-01-16T15:31:50Z (11 months ago)
  • [`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 by user avatar toraritte‭ · 2024-01-05T15:57:48Z (11 months ago)
[`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