Records

Records: key points

Product type with named elements called fields.

Alternative to tuples when they are imprecise, for instance float * float:

  • Point? Coordinates? Vector?

  • Real and imaginary parts of a complex number?

Alleviate the doubt by naming both the type and its elements:

type Point = { X: float; Y: float }
type Coordinate = { Latitude: float; Longitude: float }
type ComplexNumber = { Real: float; Imaginary: float }

Declaration

Base syntax:

type RecordName =
    { Label1: type1
      Label2: type2
      ... }

☝️ Field labels in PascalCase, not camelCase β†’ see MS style guide

Complete syntax:

Formatting styles

  • Single-line: properties separated by ;

  • Multi-line: properties separated by line breaks

    • 3 variations: Cramped, Aligned, Stroustrup

Styles comparison

Criterion
Best styles πŸ†

Compactness

Single-line, Cramped

Refacto Easiness (re)indentation, fields (re)ordering

Aligned, Stroustrup

☝️ Recommendation: Strive for Consistency β†’ Apply consistently the same multi-line style across a repository β†’ In addition, use the single-line style when relevant: line with < 80 chars

Styles configuration

Fantomas configuration in the .editorconfig file:

πŸ”— https://fsprojects.github.io/fantomas/docs/end-users/Configuration.html#fsharp_record_multiline_formatter

Members

πŸ‘‰ Members are declared after the fields

Single-line style

Multi-line Cramped and Aligned styles

☝️ 2 line breaks

Multi-line Stroustrup style

☝️ with keyword + 1 line break + indentation

Construction: record expression

  • Same syntax as an anonymous Cβ™― object without the new keyword

  • All fields must be populated, but in any order (but can be confusing)

  • Same possible styles: single/multi-lines

⚠️ Trap: differences declaration / instantiation β†’ : for field type in record declaration β†’ = for field value in record expression

Deconstruction

  • Fields are accessible by "dotting" into the object

  • Alternative: deconstruction

    • Same syntax for deconstructing a Record as for creating it πŸ‘

    • Unused fields can be ignored πŸ’‘

⚠️ Additional members (properties) cannot be deconstructed!

Inference

  • A record type can be inferred from the fields used πŸ‘ but not with members ❗

  • As soon as the type is inferred, IntelliSense will work

Pattern matching

Let's use an example: inhabitantOf is a function giving the inhabitant's name (in French) at a given address (in France)

Name conflict

In Fβ™―, typing is nominal, not structural as in TypeScript β†’ Use qualification to resolve ambiguity β†’ Even better: write β‰  types or put them in β‰  modules

Modification: copy and update

Record is immutable, but easy to get a modified copy β†’ copy and update expression of a Record β†’ use multi-line formatting for long expressions

Copy and update: Cβ™― vs Fβ™― vs JS

Copy and update limits (< Fβ™― 8)

Reduced readability with several nested levels

Copy and update: Fβ™― 8 improvements

Qualification

Last updated

Was this helpful?