From fe2fba764886a4a10503e588ab5c68bbfeb8abcb Mon Sep 17 00:00:00 2001 From: Rob Lenders Date: Sat, 10 Aug 2024 18:33:22 -0500 Subject: [PATCH 1/3] RFC FS-1146 - Ease Units of Measure --- RFCs/FS-1146-units.md | 67 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 RFCs/FS-1146-units.md diff --git a/RFCs/FS-1146-units.md b/RFCs/FS-1146-units.md new file mode 100644 index 00000000..7e7adbd9 --- /dev/null +++ b/RFCs/FS-1146-units.md @@ -0,0 +1,67 @@ +# F# RFC FS-1146 - Ease conversion between Units of Measure (UoM) and undecorated numerals and simplify casting + +The design suggestion [Ease conversion between Units of Measure (UoM) and undecorated numerals and simplify casting](https://github.com/fsharp/fslang-suggestions/issues/892) has been marked "approved in principle". + +This RFC covers the detailed proposal for this suggestion. + +- [x] [Suggestion](https://github.com/fsharp/fslang-suggestions/issues/892) +- [x] Approved in principle +- [x] [Implementation](https://github.com/dotnet/fsharp/pull/17518) +- [ ] Discussion + +## Summary + +A new type `Units` will be added to FSharp.Core and provide `static` methods for addition, removal and casting of UoM for supported primitive types and common collections containing primitive types. + +## Motivation + +Prior to this RFC, F# programmers have been able to apply units of measure supported primitive types through the use of functions in the `LanguagePrimitives` module e.g. `LanguagePrimitives.FloatWithMeasure<'M>`, or, by multiplying the value by one `1.0`. It has been commonly asked by the community for a simple way to remove units of measure from a given value or a way to convert units of measure from one unit to another directly. It has also been requested that there should be a way to convert collections of primitives e.g. `int[]` to `int[]` without having to create a copy of the collection. + +## Detailed design + +### FSharp.Core additions + +The additions follow a common pattern: + +- An overloaded `Add` method for each of the supported primitive types adds a UoM to the value +- An overloaded `Remove` method for each of the supported primitive types removed UoM from the value +- An overloaded `Cast` method for each of the supported primitive types replaces UoM on the value +- Overloaded `Add*`, `Remove*` and `Cast*` e.g. `AddArray` for common collection types containing supported primitives. + +```fsharp +namespace Microsoft.FSharp.Core + + +type Units = + static member inline Add<[]'Measure>(input: byte):byte<'Measure> = retype input + static member inline Add<[]'Measure>(input: float):float<'Measure> = retype input + ... + static member inline Remove<[]'Measure>(input: byte<'Measure>):byte = retype input + static member inline Remove<[]'Measure>(input: float<'Measure>):float = retype input + ... + static member inline Cast<[]'MeasureIn, []'MeasureOut>(input: byte<'MeasureIn>):byte<'MeasureOut> = retype input + static member inline Cast<[]'MeasureIn, []'MeasureOut>(input: float<'MeasureIn>):float<'MeasureOut> = retype input + ... + static member inline AddArray<[]'Measure>(input: byte[]):byte<'Measure>[] = retype input +``` + +### Drawbacks + +- `FSharp.Core` already offers some of the functionality in the `LanguagePrimitives` module however this has not been easy to discover for users. + +### Alternatives + +- Don't do this and maintain status quo +- Make the additions to `LanguagePrimitives` +- Use different type and/or method names +- Modify the F# language to provide a generic way to perform unit conversions - this would require the addition of `'T<'m>` as a language concept. + +### Compatibility + +This is not a breaking change. The elaboration of existing code that passes type checking is not changed. + +This doesn't extend the F# metadata format. + +### Unresolved questions + +- Should any other collections be added? From b9402520db5490fbd250f4a6e51464edc270f17d Mon Sep 17 00:00:00 2001 From: Rob Lenders Date: Sat, 10 Aug 2024 18:34:49 -0500 Subject: [PATCH 2/3] Renumbering --- RFCs/{FS-1146-units.md => FS-1148-units.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename RFCs/{FS-1146-units.md => FS-1148-units.md} (98%) diff --git a/RFCs/FS-1146-units.md b/RFCs/FS-1148-units.md similarity index 98% rename from RFCs/FS-1146-units.md rename to RFCs/FS-1148-units.md index 7e7adbd9..f9baa0d8 100644 --- a/RFCs/FS-1146-units.md +++ b/RFCs/FS-1148-units.md @@ -1,4 +1,4 @@ -# F# RFC FS-1146 - Ease conversion between Units of Measure (UoM) and undecorated numerals and simplify casting +# F# RFC FS-1148 - Ease conversion between Units of Measure (UoM) and undecorated numerals and simplify casting The design suggestion [Ease conversion between Units of Measure (UoM) and undecorated numerals and simplify casting](https://github.com/fsharp/fslang-suggestions/issues/892) has been marked "approved in principle". From c61f8dac219ba80d7ed0b6ca23492e7d9fe7df4e Mon Sep 17 00:00:00 2001 From: Rob Lenders Date: Sun, 11 Aug 2024 15:47:26 -0500 Subject: [PATCH 3/3] Add note about total methods and use of overloads --- RFCs/FS-1148-units.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/RFCs/FS-1148-units.md b/RFCs/FS-1148-units.md index f9baa0d8..2d5ee682 100644 --- a/RFCs/FS-1148-units.md +++ b/RFCs/FS-1148-units.md @@ -26,7 +26,13 @@ The additions follow a common pattern: - An overloaded `Add` method for each of the supported primitive types adds a UoM to the value - An overloaded `Remove` method for each of the supported primitive types removed UoM from the value - An overloaded `Cast` method for each of the supported primitive types replaces UoM on the value -- Overloaded `Add*`, `Remove*` and `Cast*` e.g. `AddArray` for common collection types containing supported primitives. +- Overloaded `Add*`, `Remove*` and `Cast*` e.g. `AddArray` for common collection types containing supported primitives: + - `Array` + - `List` + - `ResizeArray` + - `Seq` + +Total added methods is 195 `13 supported primitives * 3 methods * (primitive + 4 collection types)`. They are presented as 15 methods with 13 overloads each. ```fsharp namespace Microsoft.FSharp.Core @@ -65,3 +71,4 @@ This doesn't extend the F# metadata format. ### Unresolved questions - Should any other collections be added? +- The use of overloaded methods is not typical for FSharp.Core design. Is it acceptable here?