Collections.Generic.IList<obj> in F#? Issue with Google.Apis.Sheets NuGet package

Hello!

For a project I have been working on I need to update a Google Sheet. I’m using the Google.Apis.Sheets NuGet package
(JavaScript quickstart  |  Google Sheets  |  Google for Developers).

To update cells in a sheet, you make an instance of Google.Apis.Sheets.v4.Data.ValueRange(), like so:

let valueRange = new Google.Apis.Sheets.v4.Data.ValueRange()

And then you set the value property:

valueRange.Values <- values

The problem is that Values expects a Collections.Generic.IList<Collections.Generic.IList<obj>>, and I can not figure out what’s really expected (since it’s an interface). The API documentation says the following:

The data that was read or to be written. This is an array of arrays, the outer array representing all the data and each inner array representing a major dimension. Each item in the inner array corresponds with one cell.

For output, empty trailing rows and columns will not be included.

For input, supported value types are: bool, string, and double. Null values will be skipped. To set a cell to an empty value, set the string value to an empty string.

No help there. The only way I found to set the values is to use an array directly (which will be too tedious and impracticable to do):

valueRange.Values <- [| [|"cell1"; "cell2"|]|]

What’s interesting is that this does not work:

let values = [| [|"cell1"; "cell2"|]|]
valueRange.Values <- values

It gives the following error:

The type 'Collections.Generic.IList<obj>' does not match the type 'string []'

Not sure if this is relevant, but in C# one can set the property like this:

var values = new List<object>() { "cell1" };
valueRange.Values = new List<IList<object>> { values };

Can someone please shed some light on this issue? It would be highly appreciated!

You’re hitting a problem because F# doesn’t support implicit conversions the same way that C# does. In your C# example, the string “cell1” is implicitly converted to object, and List<object> is implicitly converted to IList<object>, and List<IList<object>> is implicitly converted to IList<IList<object>>.
You can do this in F# as well, you just have to explicitly cast in these cases:

open System.Collections.Generic
let innerList : IList<obj> = [| box "hi" |] :> _
let things: IList<_> = [| innerList |] :> _
let range = new Google.Apis.Sheets.v4.Data.ValueRange()
range.Values <- things

At each step of the way I had to do casting. I had to cast the string to object via the box function, and I had to cast the arrays to IList<object> and IList<IList<object>> as well. I was able to save some characters by letting things's type be inferred by using _.

4 Likes

Wow, thanks! Did not expect to get a reply this fast. Truly grateful for your help :raised_hands:

2 Likes