Why do F# closures have the [<Serializable>]
attribute? What would be a practical use case?
This code demonstrates serializing and deserializing a closure:
open System
open System.IO
open System.Runtime.Serialization.Formatters.Binary
let formatter = BinaryFormatter ()
let addTwo = (+) 2
(addTwo.GetType ()).GetCustomAttributes false
|> Array.iter (fun attribute ->
printfn "Closure has attribute: %s" (attribute.GetType ()).Name
)
let serializedClosure =
use memStream = new MemoryStream ()
formatter.Serialize (memStream, addTwo)
memStream.ToArray ()
Array.length serializedClosure
|> printfn "Serialized closure length: %d bytes"
let deserializedClosure =
use memStream = new MemoryStream (serializedClosure)
formatter.Deserialize memStream :?> Int32 -> Int32
deserializedClosure 3
|> printfn "Invoking deserialized closure: 2 + 3 = %d"
printfn "Press any key to exit..."
Console.ReadKey true |> ignore
This works because the closure is compiled into a class (note the serializable
keyword:
.class nested assembly auto ansi serializable beforefieldinit addTwo@6
extends class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<int32, int32>
{
.method assembly specialname rtspecialname instance void .ctor () cil managed {...}
.method public strict virtual instance int32 Invoke (int32 y) cil managed {...}
}
Since closure names (like addTwo@6
) are completely compiler-dependent and change even when modifying the code only a little, I was wondering what the rationale behind making closures serializable is?