Skip to content

Commit

Permalink
minor suggested edits to recently edited RFC. (#579)
Browse files Browse the repository at this point in the history
  • Loading branch information
smoothdeveloper authored May 30, 2021
1 parent e558edb commit 454fac4
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 30 deletions.
66 changes: 41 additions & 25 deletions RFCs/FS-1093-additional-conversions.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ This RFC extends F# to include type-directed conversions when known type informa
1. Puts in place a general backwards-compatible mechanism for type directed conversions (and one that works in conjunction with the existing techniques to allow subsumption at some specific places)

2. Selects a particular set of type directed conversions to use. These are currently
- the existing func --> delegate type directed conversions
- the existing delegate --> LINQ Expression type directed conversions
- the existing func (`'a -> 'b`) --> `delegate` type directed conversions
- the existing `delegate` --> LINQ `Expression` type directed conversions
- upcasting
- int32 --> int64/float32/float64
- float32 --> float64
- op_Implicit when both source and destination are nominal.
- `int32` --> `int64`/`float32`/`float64`
- `float32` --> `float64`
- `op_Implicit` when both source and destination are nominal.

3. Implements an opt-in warning when any of these are used (outside existing uses of upcasting)

Expand All @@ -37,11 +37,11 @@ The intent of this RFC is to give a user experience where:

3. Fewer upcasts are needed when programming with types that support subtyping

4. Fewer widening conversions are needed when mixing int32, float32 and float64.
4. Fewer widening conversions are needed when mixing `int32`, `float32` and `float64`.

5. Numeric int64/float32/float64 data in tuple, list and array expressions looks nicer
5. Numeric `int64`/`float32`/`float64` data in tuple, list and array expressions looks nicer

6. Working with new numeric types such as System.Half whose design includes op_Implicit should be less irritating
6. Working with new numeric types such as System.Half whose design includes `op_Implicit` should be less irritating

7. Inadvertent use of the mechanism should not introduce confusion or bugs

Expand Down Expand Up @@ -76,8 +76,10 @@ let a : obj list = [1; 2; 3] // ✅ This works
but this raised an error:

```fsharp
let a : int seq = [1; 2; 3] // ❌ error FS0001: This expression was expected to have type 'seq<int>' but here has type ''a list'
let b : obj seq = [1; 2; 3] // ❌ error FS0001: This expression was expected to have type 'seq<int>' but here has type ''a list'
let a : int seq = [1; 2; 3]
// ❌ error FS0001: This expression was expected to have type 'seq<int>' but here has type ''a list'
let b : obj seq = [1; 2; 3]
// ❌ error FS0001: This expression was expected to have type 'seq<int>' but here has type ''a list'
```

Or, alternatively, at return position, consider this:
Expand All @@ -86,7 +88,8 @@ Or, alternatively, at return position, consider this:
type A() = class end
type B() = inherit A()
type C() = inherit A()
let f () : A = if true then B() else C() // ❌ error FS0001: This expression was expected to have type 'A' but here has type 'B'
let f () : A = if true then B() else C()
// ❌ error FS0001: This expression was expected to have type 'A' but here has type 'B'
```

Or, alternatively, at constructions of data such as options, consider this:
Expand All @@ -96,8 +99,10 @@ type A() = class end
type B() = inherit A()
let f2 (x: A option) = ()
let (data: A option) = Some (B()) // ❌ error FS0001: This expression was expected to have type 'A' but here has type 'B'
f2 (Some (B()) // ❌ error FS0001: This expression was expected to have type 'A' but here has type 'B'
let (data: A option) = Some (B())
// ❌ error FS0001: This expression was expected to have type 'A' but here has type 'B'
f2 (Some (B())
// ❌ error FS0001: This expression was expected to have type 'A' but here has type 'B'
```

Instead, in all cases, prior to this RFC type upcasts or `box` are needed:
Expand All @@ -121,36 +126,44 @@ as possible. These include:

- Auto-introduction of conversions for assignments into mutable record fields and some other places with known type information.

### Motivation for int32 --> int64 type-directed conversion
### Motivation for `int32` --> `int64` type-directed conversion

The primary use case is using integer literals in int64 data.
APIs using 64-bit integers are very common in some domains. For example, in a typical tensor library shapes are given using `int64[]`. So it is
frequent to write `[| 6L; 5L |]`. There is a reasonable case to writing `[| 6; 5 |]` instead when the types are known.

Note a non-array-literal expression of type `int[]` still need to be explicitly converted to `int64[]`.

### Motivation for int32 --> single/double type-directed conversion
### Motivation for `int32` --> `single`/`double` type-directed conversion

The primary use case is using integer literals in floating point data such as `[| 1.1; 3.4; 6; 7 |]` when the types are known.

### Motivation for single --> double type-directed conversion
### Motivation for `single` --> `double` type-directed conversion

The motivations for this is fairly weak. For example it allows floating point utility code (e.g. printing) to use 64-bit floating point
values, and yet be routinely usable with 32-bit values. However a non-array-literal value of `single[]` still need to be converted to `double[]`.

### Motivation for op_Implicit type-directed conversion
### Motivation for `op_Implicit` type-directed conversion

* Certain newer .NET APIs, such as those in ASP.NET Core, make frequent use of `op_Implicit` conversions. For example,
many APIs in `Microsoft.Net.Http.Headers` make use of `StringSegment` arguments, where C# devs can just pass a
string, but F# devs must explicitly call op_Implicit all over the place
Certain newer .NET APIs (like ASP.NET Core) as well as popular 3rd party libraries, make frequent use of `op_Implicit` conversions.

Examples
* many APIs in `Microsoft.Net.Http.Headers` make use of `StringSegment` arguments
* (MassTransit)[https://github.com/MassTransit/MassTransit] uses `RequestTimeout`, which has conversion from `TimeSpan` as well as `int` (milliseconds), seemingly for a simpler API with fewer overloads
* (Eto.Forms)[https://github.com/picoe/Eto/] uses implicit constructor for many entities.

* Some popular 3rd party libraries also use `op_Implicit`. E.g. MassTransit uses `RequestTimeout`, which has an `op_Implicit` conversion from `TimeSpan` as well as `int` (milliseconds), seemingly for a simpler API with fewer overloads.
Remarks:

* In those cases, C# devs can just pass a string, but F# devs must explicitly call op_Implicit all over the place.
* One thing to watch out for is `op_Implicit` conversions to another type. E.g. `StringSegment` has conversions to `ReadOnlySpan<char>` and `ReadOnlyMemory<char>`.

### Motivation for completing the matrix of integer widenings

If `op_Implicit` is accetped as a type-directed conversion then there is also an additional "consistency" motivation to include `int8` --> `int16` --> `int32` --> `int64` and similar widenings. Specifically additional .NET numeric types such as `System.Half`, `System.Decimal` and `System.Complex` do allow certain implicit conversions via `op_Implicit`. So if these types have widening from `int8`, `int16` and `int32` then why doesn't `System.Int64`?
If `op_Implicit` is accetped as a type-directed conversion then there is also an additional "consistency" motivation to include `int8` --> `int16` --> `int32` --> `int64` and similar widenings.

Specifically additional .NET numeric types such as `System.Half`, `System.Decimal` and `System.Complex` do allow certain implicit conversions via `op_Implicit`.

So if these types have widening from `int8`, `int16` and `int32` then why doesn't `System.Int64`?

# Detailed design

Expand Down Expand Up @@ -289,7 +302,8 @@ type C() = inherit A()
let Plot (elements: A list) = ()
[B(); C()] |> Plot // ❌ error FS0193: Type constraint mismatch. The type 'C' is not compatible with type 'B'
[B(); C()] |> Plot
// ❌ error FS0193: Type constraint mismatch. The type 'C' is not compatible with type 'B'
```

This RFC change will not address this example - the element type of the list is inferred to be `B`. This however works:
Expand All @@ -307,7 +321,8 @@ Some newly allowed calls may not be tailcalls, e.g.:

```fsharp
let f1 () : int = 4
let f2 () : obj = f1() // this is not a tailcall, since an implicit boxing conversion happens on return
let f2 () : obj = f1()
// this is not a tailcall, since an implicit boxing conversion happens on return
```

Turning on the optional warning and removing all use of type-directed conversions from your code can avoid this if necessary.
Expand Down Expand Up @@ -408,7 +423,8 @@ Note consider the following seemingly routine extraction:
let g() =
let data1 = (1, "2")
let data2 = (3, "4")
f [ data1; data2 ] // ❌ error FS0001: Type mismatch. Expecting a 'obj * obj' but given a 'int * string'. The type 'obj' does not match the type 'int'.
f [ data1; data2 ]
// ❌ error FS0001: Type mismatch. Expecting a 'obj * obj' but given a 'int * string'. The type 'obj' does not match the type 'int'.
```

Here, `data1` now needs a type annotation to maintain the same inferred type. This matters because `data` is a tuple, and, in the absence of
Expand Down
6 changes: 3 additions & 3 deletions RFCs/FS-1097-task-builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ The design suggestion [Native support for task { ... } ](https://github.com/fsha

# Summary

We add a `task { .. }` builder to the F# standard library, implemented using [resumable code](https://github.com/fsharp/fslang-design/blob/master/RFCs/FS-1087-resumable-code.md).
We add a `task { .. }` builder to the F# standard library, implemented using [FS-1087 resumable code](https://github.com/fsharp/fslang-design/blob/master/RFCs/FS-1087-resumable-code.md).

The design is heavily influenced by [TaskBuilder.fs](https://github.com/rspeele/TaskBuilder.fs/) and [Ply](https://github.com/crowded/ply) which effectively
formed part of prototypes for this RFC (thank you!!!!)
Expand All @@ -32,7 +32,7 @@ We add support for tasks along the lines of `TaskBuilder.fs`. This supports

* `use` on both `IDisposable` and `IAsyncDisposable` resources

* `backgroundTask { ... }` to escapte the UI thread synchronization context
* `backgroundTask { ... }` to escape the UI thread synchronization context

For example, a simple task:
```fsharp
Expand Down Expand Up @@ -162,7 +162,7 @@ A `vtask { ... }` is definable as a user-library using resumable code, replicat
### IAsyncDisposable

If `netstandard2.1` FSHarp.Core.dll or higher is referenced, then the following method is available directly on the TaskBuilder type:
If `netstandard2.1` FSharp.Core.dll or higher is referenced, then the following method is available directly on the TaskBuilder type:

```fsharp
type TaskBuilderBase =
Expand Down
4 changes: 3 additions & 1 deletion RFCs/FS-1099-list-collector.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ This RFC covers the detailed proposal for the resumable state machine support ne

# Summary

TBD
Optimize runtime cost of list and array expressions. Those currently rely on the Sequence expression infrastructure.

In conjunction with [FS-1087 resumable code](FS-1087-resumable-code.md), this open alley for performance gains.

# Detailed Design
```fsharp
Expand Down
2 changes: 1 addition & 1 deletion RFCs/FS-1100-Printf-binary.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ This RFC covers the detailed proposal for this suggestion.
# Summary

An additional format specifier `%B` will be added to F# which formats a basic integer type
(currently (byte|int16|int32|int64|sbyte|uint16|uint32|uint64|nativeint|unativeint))
(currently `byte`|`int16`|`int32`|`int64`|`sbyte`|`uint16`|`uint32`|`uint64`|`nativeint`|`unativeint`)
as an unsigned binary number.

# Motivation
Expand Down

0 comments on commit 454fac4

Please sign in to comment.