docs icon indicating copy to clipboard operation
docs copied to clipboard

Anonymous records are not nominal

Open IS4Code opened this issue 7 months ago • 2 comments

Type of issue

Outdated article

Description

The paragraph:

Anonymous records are nominal types. They are best thought of as named record types (which are also nominal) that do not require an up-front declaration.

is misleading ‒ the code goes to show that anonymous records with different members are incompatible, but I am not sure what that is supposed to prove ‒ int * int is also incompatible with string * string and I haven't heard one call tuples nominal.

This should be the real proof:

type R1 = { X: int }
type R2 = { X: int }

let r1 : R1[] = [| |]
let r2 : R2[] = r1 // error - type mismatch

type AR1 = {| X: int |}
type AR2 = {| X: int |}

let ar1 : AR1[] = [| |]
let ar2 : AR2[] = ar1 // fine - AR2 is identical to AR1

Two declarations with a different name but same structure being equivalent is exactly what a structural system exhibits, as opposed to a nominal one.

Page URL

https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/anonymous-records

Content source URL

https://github.com/dotnet/docs/blob/main/docs/fsharp/language-reference/anonymous-records.md

Document Version Independent Id

7c5955cd-60ba-12a6-8661-d9b9b7700cf1

Platform Id

178aabe3-cc05-5195-37e1-d1bd63900af6

Article author

@KathleenDollard

Metadata

  • ID: b69dfedf-d03a-1733-5c06-7b2000bad772
  • PlatformId: 178aabe3-cc05-5195-37e1-d1bd63900af6
  • Service: dotnet-fsharp

Related Issues

IS4Code avatar May 09 '25 10:05 IS4Code

@T-Gro @KathleenDollard Thoughts?

BillWagner avatar May 09 '25 14:05 BillWagner

This issue is correct - the examples does not prove much about nominality. With regular records, the nominality comes from the fully qualified name.

For anonymous records, nominality is from using the exact same set of fields and field types.

I think this section is not adding much by speaking about nominal types (as opposed to e.g. positional types, tuples) - we might end up better removing that sub-section alltogether.

let a = {| X = 1; Y = false |}
let b = {| Y = true; X = 5 |}
// We can compare a and b. They are same by using same fields


let tup1 = (1,true)
let tup2 = (false,5)
// We cannot compare two tuples, since the order is switched - tuples are positional types

But as written above, even though an explanation is possible, I do not see much value of describing it here. It's type-theory interesting, not end-user interesting I would say.

T-Gro avatar May 12 '25 14:05 T-Gro