SAFE-template icon indicating copy to clipboard operation
SAFE-template copied to clipboard

Boxing / unboxing: unboxed list has length 0 (unboxing as an array works however)

Open reneederer opened this issue 3 years ago • 4 comments

Hi,

from the server, I return a boxed list

box [ DateTimeOffset.MinValue; DateTimeOffset.MaxValue ]

On the client, unboxing via

let datesAsList = unbox<DateTimeOffset list> datesFromServer
printfn $"datesAsList: length: {datesAsList.Length}, dates: {datesAsList}"

let datesAsArray = unbox<DateTimeOffset array> datesFromServer
printfn $"datesAsArray: length: {datesAsArray.Length}, dates: {datesAsArray}"

prints

datesAsList: length: 0, dates: 0001-01-01T00:00:00+00:00,9999-12-31T23:59:59.9999999+00:00
datesAsArray: length: 2, dates: 0001-01-01T00:00:00+00:00,9999-12-31T23:59:59.9999999+00:00

I would have expected: datesAsList has length 2, datesAsArray throws an exception.

Furthermore, trying to access datesAsArray.[0].DateTime throws

Uncaught TypeError: date.getTime is not a function
    at fromDateTimeOffset (Date.js?a63a:161:1)
    at eval (SearchTable.fs?840b:498:51)
    at map (Array.js?34b9:77:1)

I found an ugly workaround with

unbox<string array> datesFromServer
|> Array.map DateTimeOffset.Parse
|> List.ofArray

reneederer avatar Mar 22 '22 09:03 reneederer

@reneederer Why do you return a boxed list from the server?

Zaid-Ajaj avatar Mar 22 '22 10:03 Zaid-Ajaj

On the client, I need to display a table with different column types. One of the columns has cells that contain list of dates. I fetch the table rows from the server as list<list<obj>>, and in the date-column-case, obj is list<DateTimeOffset> Capture

Is this understandable? Can I solve it without boxing/unboxing?

reneederer avatar Mar 22 '22 10:03 reneederer

@reneederer I see, working with dynamic data can be annoying. Note that on the client side, unbox doesn't do anything at runtime! This is not a bug, that's by design. So depending on the shape of data (list<list<obj>> in this case) the runtime representation might not be unboxable to the type you want.

I do suggest you use a proper type for sending data from server to client:

[<RequireQualififedAccess>]
type TableField = 
  | Text of string
  | Date of DateTimeOffset
  | List of TableField list

type TableRow = TableRow of Map<string, TableField>

type DatabaseApi = {
  events : unit -> Async<TableRow list>
}

Then on the client, you can try to render the data in the table or I am guessing you are using a component? Then you would have to write a utility function that converts the data into array<array<obj>> before giving that to the component

Zaid-Ajaj avatar Mar 22 '22 10:03 Zaid-Ajaj

Ok, thanks for the quick answer!

reneederer avatar Mar 22 '22 10:03 reneederer