Consider the following code, which uses FSharp.Data to request data from a web resource
let resp = Http.RequestStream(url, headers, query)
use rdr = new StreamReader(resp.ResponseStream)
use jrdr = new JsonTextReader(rdr)
let serializer = new JsonSerializer()
let myArray = serializer.Deserialize<someType[]>(jrdr).Value
myArray
is an array of someType
. Arrays are eagerly evaluated so if I request a large amount of data, I will consume a large amount of RAM up front.
What if I ask json.net to give me a seq instead?
let resp = Http.RequestStream(url, headers, query)
use rdr = new StreamReader(resp.ResponseStream)
use jrdr = new JsonTextReader(rdr)
let serializer = new JsonSerializer()
let mySeq = serializer.Deserialize<someType seq>(jrdr).Value
If I iterate through mySeq and write it to a text file, is everything pulled form the stream and deserialized lazily? Or does the act of asking json.net to deserialize force everything to be eagerly evaluated at that point?
UPDATE
Following on from the accepted answer of dbc, a functional lazy function would be something like the following
let jsonSeqFromStream<'T>(stream:Stream) = seq{
let serializer = JsonSerializer.CreateDefault()
use rdr = new StreamReader(stream, Encoding.UTF8, true, 4096, true)
use jrdr = new JsonTextReader(rdr, CloseInput = false)
let rec resSeq inArray = seq{
if jrdr.Read() then
match jrdr.TokenType with
|JsonToken.Comment -> yield! resSeq inArray
|JsonToken.StartArray when not inArray -> yield! resSeq true
|JsonToken.EndArray when inArray -> yield! resSeq false
|_ ->
let resObj = serializer.Deserialize<'T>(jrdr)
yield resObj
yield! resSeq inArray
else
()
}
yield! resSeq false
}