Proposal: Allow 'T shorthand for dummy type values in SRTP constraints
Description
When using SRTP (statically resolved type parameters) in F#, developers often need to pass a dummy value whose only purpose is to fix a type parameter that otherwise wouldn’t be inferred.
Today this requires the verbose (_: 'T) pattern, e.g.:
let inline foo (_: ^g) x y =
((^g or ^x or ^y) : (static member Foo : ^x * ^y -> unit) (x, y))
I propose allowing 'g shorthand for such dummy-value parameters:
let inline foo 'g x y =
((^g or ^x or ^y) : (static member Foo : ^x * ^y -> unit) (x, y))
This removes visual clutter while preserving semantics.
Motivation / Real-world example
The dummy-value pattern is necessary whenever the SRTP type does not appear in any of the value parameter types. A common case is when static members are grouped on a provider type, and this provider type itself does not occur in the function’s signature.
type Provider =
static member Foo(x:int, y:int) = printfn "int add: %d + %d" x y
static member Foo(x:float, y:float) = printfn "float add: %f + %f" x y
let inline foo (_: ^provider) (x: ^x) (y: ^y) =
((^provider or ^x or ^y) : (static member Foo : ^x * ^y -> unit) (x, y))
foo (Unchecked.defaultof<Provider>) 1 2
foo (Unchecked.defaultof<Provider>) 1.0 2.0
Here ^provider is required to resolve the correct static overload, but it cannot be inferred from x or y. The dummy parameter exists solely to fix the type.
With the proposed shorthand, the declaration becomes:
let inline foo 'provider x y =
((^provider or ^x or ^y) : (static member Foo : ^x * ^y -> unit) (x, y))
Pros
- Removes syntactic noise ((_: 'T)) in SRTP-heavy code.
- Makes intent clearer: 'provider is a type marker, not a real value.
- Improves readability of provider/tag-dispatch patterns.
Cons / Considerations
- Requires parser/grammar support for 'T in value-parameter position.
- Type checker changes needed to interpret 'T as a dummy value parameter.
- Needs careful design to avoid ambiguity with existing syntax.
Alternatives
- Keep the current (_: 'T) pattern (status quo).
- Official phantom type for SRTP (proposed): F# could provide a dedicated phantom type for this purpose, instead of introducing new syntax. This phantom type would act as a special SRTP carrier. It would be allowed in function parameter patterns with type arguments, e.g.:
let foo Phan<'g> x y =
((^g or ^x or ^y) : (static member Foo : ^x * ^y -> unit) (x, y))
do foo Phan<Provider> x y
- The main advantage is that you no longer need to supply a dummy runtime value (Unchecked.defaultof<_>), while using a uniform and clear model for SRTP resolution.
Checklist
-
[x] This is not a question (e.g. like one you might ask on StackOverflow) and I have searched StackOverflow for discussions of this issue
-
[x] This is a language change and not purely a tooling change (e.g. compiler bug, editor support, warning/error messages, new warning, non-breaking optimisation) belonging to the compiler and tooling repository
-
[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
-
[x] I have searched both open and closed suggestions on this site and believe this is not a duplicate
-
[x] This is not a breaking change to the F# language design
-
[ ] I or my company would be willing to help implement and/or test this