fsharp / fsharp/fslang-suggestions
Revamp treatment of optional values (esp 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.