tags:

views:

100

answers:

1

Hi,

Considering the following record types:

type drCode1Body = {DrCode : byte ; Name : string ; Timestamp : DateTime ; Size : uint32 ; Options : byte}
type drCode2Body = {DrCode : byte ; LastBlock : byte ; BlockNumber : uint16 ; BlockSize : uint16 ; BlockData : array<byte>}
type drCode4Body = {DrCode : byte ; Name : string ; Timestamp : DateTime ; Options : byte ; Size : uint16 ; Data : array<byte>}

If I try to create instances like this (code snippets, not full code):

{DrCode = 1uy ; Name = name ; Timestamp = timestamp ; Size = size ; Options = options}        

{DrCode = 2uy ; LastBlock = lastBlock ; BlockNumber = blockNumber ; BlockSize = blockSize ; BlockData = blockData}

{DrCode = 4uy ; Name = name ; Timestamp = timestamp ; Options = options ; Size = size ; Data = data }

It does not accept the first line to be valid. Even though the size in the first line is a uint32 value. It simply says "no assignment given for field 'Data'."

Changing the names of the parameters does not help either, I tried this as well:

 {new drCode1Body with DrCode = 1uy and Name = name and Timestamp = timestamp and Size = size and Options = options}

Then I get the following exception:

This expression has type drCode1Body but is here used with type drCode4Body

While I am clearly indicating what record type I want here.

What's going on?

+3  A: 

You can just write e.g.

{drCode1Body.DrCode = 1uy ; Name = name ; ...

to disambiguate when record field labels overlap.

(Effectively what happens is as F# starts reading the labels, it searches backwards for the first record type with those labels... once it sees DrCode and Name, it thinks 'surely you mean drCode4Body!'... by providing diasmbiguation on the first field tag you steer the type-inference in the right direction.)

Code below compiles on F# 1.9.6.2:

#light
open System
type drCode1Body = 
  {DrCode : byte; Name : string; Timestamp : DateTime; Size : uint32; Options : byte}
type drCode2Body = 
  {DrCode : byte; LastBlock : byte; BlockNumber : uint16; BlockSize : uint16; BlockData : array<byte>}
type drCode4Body = 
  {DrCode : byte; Name : string; Timestamp : DateTime; Options : byte; Size : uint16; Data : array<byte>}
let name = ""
let timestamp = DateTime.Now 
let size = 0u
let size2 = 0us
let options = 0uy
let lastBlock = 0uy
let blockNumber = 0us
let blockSize = 0us
let blockData = [|0uy|]
let data = [|0uy|]
let r1 = {drCode1Body.DrCode = 1uy; Name = name; Timestamp = timestamp; Size = size; Options = options}        
let r2 = {DrCode = 2uy; LastBlock = lastBlock; BlockNumber = blockNumber; BlockSize = blockSize; BlockData = blockData}
let r3 = {DrCode = 4uy; Name = name; Timestamp = timestamp; Options = options; Size = size2; Data = data }
Brian
But I tried giving each record a unique DrCode name just to test like type drCode1Body = {DrCode1 : byte ... an d type drCode2Body = {DrCode2 : byte and it still has the same result
TimothyP
Even this gives the same error: {drCode1Body.DrCode = 1uy , drCode1Body.Name = name , drCode1Body.Timestamp = timestamp , drCode1Body.Size = size , drCode1Body.Options = options} But you got me on to something....
TimothyP
@TimothyP: Try this:let (r1:drCode1Body) = {DrCode = 1uy; ....let r2 = {DrCode = 2uy; ....let r3 = {DrCode = 4uy; ....It should also work, though Brian's solution works for me.
Dave Berk
Brian's solution works in some cases... I'll try yours now
TimothyP
let (r1 : drCode13Body) = {drCode13Body.DrCode = 13uy ; Number = number ; Clocks = items}r1Still thinks it's drCode15Body
TimothyP