TheSharperDev

Educating about C# and F#

Seq.cast - F#

Lets examine Seq.cast.

Seq.cast: Wraps a loosely-typed System.Collections sequence as a typed sequence. ~ FSharp.Core

And also:

Seq.cast is useful when working with older parts of the BCL (base class library) that have specialized collection classes rather than generics. ~ fsharpforfunandprofit

Generics were not an original part of .NET/C#. They weren’t supported until C# 2.0. Seq.cast is useful to convert older pregeneric collections into generic collections.

The F# docs have this example:

let unboxedExample = 
    [box 1; box 2; box 3]
 

[<EntryPoint>]
let main argv =    
    let intSeq = 
        unboxedExample 
        |> Seq.cast

    printfn "%A" intSeq
    0

Output: seq [1; 2; 3]

In F#, the box and unbox mechanisms allow primitive values (int, double, bool, etc) to behave as objects. Primitives are stack based, objects are heap based.

The usage of Seq.cast in this example “casts” that object value back into it’s primitive value.

I find the fsharpforfunandprofit example more revealing for it’s purpose. I’ve explicitly added the type of the matchCollection.

let matches =
    let pattern = "\d\d\d"
    let matchCollection: MatchCollection = Regex.Matches("123 456 789",pattern)
    matchCollection
    |> Seq.cast<Match>
    |> Seq.map (fun m -> m.Value)
    |> Seq.toList
//ouputs = ["123"; "456"; "789"]

As you can see, Regex.Matches returns a non helpful collection type, MatchCollection. Having a seq, list or array would be easier to work with.

If we first cast it to Match, now we’re working with a seq<Match>, and can use common library functions.

Notes:

  • I can’t remember a time where I needed this functionality, in either my C# or F# experience. So not something I’d see myself using soon.
  • If items in your collection can’t cast to your desired type, RuntimeException!! So be careful!