fsharp / fsharp/fslang-suggestions
Support explicit generic constraints of multiple specializations of the same generic interface
- Dominant language
- No language data
- Stars
- 373
- Forks
- 21
- PR merge metrics
- No merged PRs in 30d
Description
# Support explicit generic constraints of multiple specializations of the same generic interface
I propose we allow:
```fs
type I<'T> = abstract U : unit
let f1 (_: I) = ()
let f2 (_: I) = ()
let f3<'T when 'T :> I and 'T :> I>(x: 'T) = f1 x; f2 x
```
You currently cannot do this in F#. The reason is given here:
https://github.com/dotnet/fsharp/issues/10432#issuecomment-738324344
> There is also a relevant F# type inference limitation that may be coming into play - I haven't looked closely at the repo above but it is definitely relevant to #10516
>
> The important thing to know is this:
>
> > **When F# sees `'a :> IA` and `'a :> IA` constraints for a type inference variable `'a` then it unifies `ty1` and `ty2`.**
>
> This is by design, and one of the reasons why multiple instantiations of generic interfaces was not supported in F#.
>
> The reason this is done is that it is very, very common to have `'a :> seq` and `'a :> seq` for partially inferred types `ty1` and `ty2`. This happens everywhere in F# code and in this situation it's crucial to flow type equalities between `ty1` and `ty2`.
>
> That is, the F# type inference system simply assumes that generic code is not constrained over multiple different interface instantiations.
>
> Type definitions that implement multiple instantiations can be *used* but you can't write F# generic code over this code or structure.
>
> It would be a separate RFC to enable this in some limited cases (e.g. when full type annotations are given), though I'd also recommend just not trying to do this
>
> This may or may not be the cause of the above. On a quick glance it is the cause of #10516
> When you do `dostuff mything` or `mything |> dostuffrev` the constraint of `IA = IA` is encountered before the constraint `IA = IA` and `int` is chosen to solve the inference type `?T`.
>
> When you do `5 |> dostuff mything` or `"blah" |> dostuff mything` the solution `?T = int` or `?T = string` is pre-chosen and it is obvious (I believe via the feasibly-equivalent relationship in the compiler and language spec) that the compiler can apply the appropriate `C :> IA` or `C :> IA`
>
> Given the constraint `C :> IA` the compiler will not continue with `?T` unresolved.
>
> So this is just how it works. If you're going to use this feature you'll need type annotations and/or flowed type information.
## Pros and Cons
The advantages of making this adjustment to F# are
1. Consistency with C#
2. Convenience
3. Correctness
The disadvantage of making this adjustment to F# is that this cannot be used together effectively with type inference for the reasons as mentioned.
## Extra information
Estimated cost (XS, S, M, L, XL, XXL): M
Related suggestions:
https://github.com/dotnet/fsharp/issues/10432
https://github.com/dotnet/fsharp/issues/10516
https://github.com/dotnet/fsharp/issues/11659
## 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
## For Readers
If you would like to see this issue implemented, please click the :+1: emoji on this issue. These counts are used to generally order the suggestions by engagement.
Contributor guide
No contributing guide indexed for this repository
Research direction
No source files, tests, or compiler entry points are named. Start by reviewing related issues #10432, #10516, and #11659 alongside the type-inference rationale; done means agreeing on an approach that supports multiple specialized interface constraints without disrupting existing inference behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- fsharp
- Domain
- compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 30/100