fsharp / fsharp/fslang-suggestions

Revamp treatment of optional values (esp records)

Open
#617 35 comments 34 reactions 0 assignees View on GitHub
area: records
Dominant language
No language data
Stars
373
Forks
21
PR merge metrics
No merged PRs in 30d

Description

The current record constructors are problematic, because if you add a field to it, everywhere that uses it is broken. Adding a field to a record is therefore often not backwards compatible, which is a big downside, and leads to some authors avoiding records altogether if they may be exposed externally.

This is a shame, because records and the record construction syntax are otherwise fantastic parts of F#.

# Solution: Better record construction syntax

To solve this problem, I propose we add a new record construction syntax that is more clear, more tooling friendly, more concise, and less brittle. The current record constructors are problematic, because if you add a field

Summary:
1. Introduce `%RecordName { ... } ` syntax for constructing records (stolen from elixir)
2. Allow omitting fields with obvious "zero" values (such as `None` for `option`)
- `null` for reference types does not count
3. In addition to 2, or instead of 2: Allow omitting fields for fields that have a default defined in the record definition

Examples:

```fsharp
type Person = { fullName: string; email: string option; }

// A symbol like `%` (stolen from elixir) to say you want to start creating the record
// We leave out the optional field "email" here, and it still compiles. It will be set to None.
let person1 = %Person { fullName = "Don Syme"; }

// This does NOT compile, because fullName is not an option, and we don't want to encourage null values
let person3 = %Person { }

// Some other cases to consider
type InventoryRow = { name: string; weight: float; tags: string list; quantity: int }
let row1 = %InventoryRow { name = "Bungie" }
// This would be equivalent to:
let row2 = { name = "Bungie"; weight = 0.0f; tags = []; quantity = 0 }
```

For the alternative version:

```fsharp
type InventoryRow =
{ name: string = "";
weight: float;
tags: string list = ["unlabeled"];
quantity: int = 1 }

let row1 = %InventoryRow { weight = 1.0f } // allowed

// no weight specified, a field that has no default specified.
// Allowed only if we go with AND for part 3 of the suggestion
let row2 = %InventoryRow { }
```

## Pros and Cons

- Adding an optional field to a record will no longer lead to tons of compilation errors all over your codebase (everywhere you used record construction syntax)
- When typing your code, you type your intent to make a new X record at the very beginning, which leads to better / easier to implement editor support
- Faster type checking
- Better error messages
- Increased clarity

The disadvantages of making this adjustment to F# are ...

- There would be more than 1 way to construct records, adding confusion.

## Extra information

For point 2 of the summary, some implicit defaults to consider for types:

- Option : None
- Collections: Empty collections
- Numbers : 0
- Built in non-numbers that have a .MinValue property. for example TimeSpan, DateTime.

Somewhat related: [Kotlin data classes](https://kotlinlang.org/docs/reference/data-classes.html).

Estimated cost (XS, S, M, L, XL, XXL): Unknown.

Related suggestions: (put links to related suggestions here)

## Affidavit (please submit!)

Please tick this by placing a cross in the box:
* [x] This is not a question (e.g. like one you might ask on [stackoverflow](http://stackoverflow.com)) and I have searched stackoverflow for discussions of this issue
* [x] I have [searched both open and closed suggestions on this site](http://github.com/fsharp/fslang-suggestions/issues) and believe this is not a duplicate
* [x] This is not something which has obviously "already been decided" in previous versions of F#. If you're questioning a fundamental design decision that has obviously already been taken (e.g. "Make F# untyped") then please don't submit it.

Please tick all that apply:
* [x] This is not a breaking change to the F# language design
* [x] I or my company would be willing to help implement and/or test this

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.