Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.NET 9 compat features assessment #16967

Closed
vzarytovskii opened this issue Mar 28, 2024 · 13 comments
Closed

.NET 9 compat features assessment #16967

vzarytovskii opened this issue Mar 28, 2024 · 13 comments
Labels
Area-Compiler-ImportAndInterop import of .NET DLLs and interop
Milestone

Comments

@vzarytovskii
Copy link
Member

vzarytovskii commented Mar 28, 2024

We need to assess which features we will need to support in F# 9

  1. Params collections: developers can now put params in front of many more collection types in signatures including Span.

    • Minimum (targeted for F# 9): Make sure F# compiler can work with those, even if F# user has to construct collection type by hand
    • Extra (out of the picture for F# 9): Implement the Span+ReadOnly span part of the proposal
    • Full support (out of the picture for F# 9): F# compiler has to learn all the rules on how to construct collection on behalf of the developer (i.e. translate from MethodCall(1,2,3) to MethodCall(MyFancyType.Create().Add(1).Add(3).Add(3)) or similar following the full spec
  2. ref struct generics and interfaces :
    A ref struct can now both implement an interface

  3. A type parameter can now be (anti)constrained to allow ref struct arguments

    • Minimum (targeted for F# 9): Consume types with these constraints, and full tooling support.
    • Full support (out of the picture for F# 9): Author such types in F# (because of escape analysis rules).
    • Covered by Support ref structs in generics #16800
  4. Extension types: this is a new way of declaring extension members (both static and instance)

    Cut from C# for .NET9, so we don't need to do it now - Minimum (targeted for F# 9): Support calling methods with such augmented types (extensions). C# feature still has a lot of TODOs, which means we'll likely won't be able to start working on it until C# has a working prototype implemented. This will still need an RFC and design. - 3 design decisions will need to be made: - Support for extension members - Support for extension static members - Support for extension that implement interfaces - Support of such extensions in SRTPs. - Full support (out of the picture for F# 9): Shall there be an abillity to declare such extensions for consumption from both F# and C# (i.e. expanding our type augmenation and extensions support). This is up to @dsyme to approve/reject.
  5. Overload resolution priority: developers can add weight to which methods are better in overload resolution. This seems unlikely to impact F# as much.

    • Minimum (targeted for F# 9): Making sure everything works as expected (i.e. as if there's no attribute)
    • Extra (might be targeted for F# 9 if there's capacity): If attribute is present, incorporate sorting by this attributes in case of conflicts (i.e. only if F# would complain about not being able to pick a method anyway) => minimal risk of breaks.
    • Full support (out of the picture for F# 9): Reverse engineer the method resolution spec changes, transform and adapt into a new suggestion+F# RFC which changes method resolution incl. relevant type inference changes (not covered in the C# spec).

We will likely need to look at 1 and see it doesn't break, but no rush supporting it in F# 9 (since we're pretty much at capacity currently), 2 and 3 will need to be supported, 4 is the same as 1 for the release (i.e. make sure nothing is breaking, wider support will require separate design based on final set of features implemented in C#), 5 will be likely out of the picture for F# 9.

@edgarfgp
Copy link
Contributor

@vzarytovskii Will fsharp/fslang-suggestions#905 also be part of 5. Overload resolution priority ?

@vzarytovskii
Copy link
Member Author

vzarytovskii commented Apr 17, 2024

@vzarytovskii Will fsharp/fslang-suggestions#905 also be part of 5. Overload resolution priority ?

No, linked suggesting is F# specific feature and not connected with C# attribute proposal. 5 will likely not be worked on for F# 9, since it shouldn't be affecting existing method resolution rules.

@vzarytovskii
Copy link
Member Author

To expand: the issues above are only about .NET 9 and compatibility, any existing F# suggestions will likely be orthogonal to any above. The approach would likely be to go the path the least resistance, and make sure "everything works". Later on (F# 10+) decide whether any extended support is needed/desired.
Reasoning for that is, well, we want it to work, but we want to see how the feature expands in C#/runtime after release and what level of support is adequate for F#, so we can properly plan and design the it.

@dsyme
Copy link
Contributor

dsyme commented Apr 17, 2024

@vzarytovskii This is a great list!

Full support (out of the picture for F# 9): Shall there be an ability to declare such extensions for consumption from both F# and C# (i.e. expanding our type augmentation and extensions support). This is up to @dsyme to approve/reject.

I think it's reasonable to support this - so yes, approved-in-principle - though it opens many smaller questions. The question is really about how to fit this with the existing mechanisms in F# for declaring extensions and I'm open to hearing community suggestions and let you and others shape the detailed design process for resolving the technical issues in this.

I assume the current compilation of current F# extensions can't "fit" with what this new thing expects. To make this palatable perhaps an attribute CLIExtension could be added to F#-style extensions to make them compile differently.

  • Failing that I'm guessing that an attributed declaration form will be possible - like [<Extension>] - for what we call "C#-style extensions". This will give three ways of declaring extensions in F# but I think it may be unavoidable.

@vzarytovskii
Copy link
Member Author

@vzarytovskii This is a great list!

Full support (out of the picture for F# 9): Shall there be an ability to declare such extensions for consumption from both F# and C# (i.e. expanding our type augmentation and extensions support). This is up to @dsyme to approve/reject.

I think it's reasonable to support this - so yes, approved-in-principle - though it opens many smaller questions. The question is really about how to fit this with the existing mechanisms in F# for declaring extensions and I'm open to hearing community suggestions and let you and others shape the detailed design process for resolving the technical issues in this.

Yeah, we'll need to wait for the implementation/finished spec on C#/CLR side and see how would that be fitting with what do we currently have in F#.

I assume the current compilation of current F# extensions can't "fit" with what this new thing expects. To make this palatable perhaps an attribute CLIExtension could be added to F#-style extensions to make them compile differently.

Probably not fully expressible with current extensions, yes.

  • Failing that I'm guessing that an attributed declaration form will be possible - like [<Extension>] - for what we call "C#-style extensions". This will give three ways of declaring extensions in F# but I think it may be unavoidable.

Yep, we'll pretty much have "one more way" of doing that.

@brianrourkeboll
Copy link
Contributor

brianrourkeboll commented Apr 17, 2024

@vzarytovskii As for the overload resolution priority attribute, I am curious what the implications of remaining unaware of it might be given a few excerpts from the proposal:

a new attribute … that can be used by API authors to adjust the relative priority of overloads … even if those APIs would normally be considered ambiguous

(emphasis mine)

The type or member is still visible in overload resolution, and may cause unwanted overload resolution failures when there is a perfectly good alternative, but that alternative is either ambiguous with the obsoleted member, or the presence of the obsoleted member causes overload resolution to end early without ever considering the good member. For this purpose, we want to have a way for API authors to guide overload resolution on resolving the ambiguity, so that they can evolve their API surface areas and steer users towards performant APIs without having to compromise the user experience.

(emphasis mine)

It sounds like the attribute would (intentionally) make it possible to create APIs that could only be disambiguated by a compiler that understood the attribute.

I left a comment on the C# issue: dotnet/csharplang#7706 (comment).

@vzarytovskii
Copy link
Member Author

@vzarytovskii As for the overload resolution priority attribute, I am curious what the implications of remaining unaware of it might be given a few excerpts from the proposal:

a new attribute … that can be used by API authors to adjust the relative priority of overloads … even if those APIs would normally be considered ambiguous

(emphasis mine)

The type or member is still visible in overload resolution, and may cause unwanted overload resolution failures when there is a perfectly good alternative, but that alternative is either ambiguous with the obsoleted member, or the presence of the obsoleted member causes overload resolution to end early without ever considering the good member. For this purpose, we want to have a way for API authors to guide overload resolution on resolving the ambiguity, so that they can evolve their API surface areas and steer users towards performant APIs without having to compromise the user experience.

(emphasis mine)

It sounds like the attribute would (intentionally) make it possible to create APIs that could only be disambiguated by a compiler that understood the attribute.

Yep, that's my understanding as well, if compiler is unaware of attribute, type resolution would work as if it was just another overload...i.e. default rules would work. Attribute is designed to hint the compiler which one to prefer specific one (e.g. string vs Span/RoS, etc) when there are multiple candidates.

I left a comment on the C# issue: dotnet/csharplang#7706 (comment).

@brianrourkeboll
Copy link
Contributor

Yep, that's my understanding as well, if compiler is unaware of attribute, type resolution would work as if it was just another overload...i.e. default rules would work.

Yeah, but doesn't this mean that there could now be (more) C# libraries whose APIs would be impossible to consume from F#? (It already is possible to define overloaded APIs in C# that are impossible to consume from F#, but this would add another way to do it.)

@jaredpar
Copy link
Member

Minimum (targeted for F# 9): Make sure F# compiler works when consuming such interfaces

The other item I would make sure to focus on is that F# can consume generics that have ref struct type arguments. This is likely to show up in a number of places in the BCL and it seems inevitable that F# users will encounter this. It's possible this is cheap for F#, or even free. But given that up until now they've been banned in generics know that both the runtime and roslyn code base had assert style guards that fired when they were encountered.

@vzarytovskii
Copy link
Member Author

Yep, that's my understanding as well, if compiler is unaware of attribute, type resolution would work as if it was just another overload...i.e. default rules would work.

Yeah, but doesn't this mean that there could now be (more) C# libraries whose APIs would be impossible to consume from F#? (It already is possible to define overloaded APIs in C# that are impossible to consume from F#, but this would add another way to do it.)

It might be, can you drop some examples here please?

@brianrourkeboll
Copy link
Contributor

It might be, can you drop some examples here please?

The proposal doesn't seem to have an example of this, but the wording implies to me that enabling such APIs to be created is part of the point of the feature: i.e., in a case where it would be impossible to disambiguate a new overload of an API from an obsolete one using the current overload resolution rules, this new attribute would enable the compiler to do so, which would allow the API author to conveniently replace usage of an obsolete API in a way that was impossible before. But that by definition sounds like it would mean that any compiler that didn't understand the attribute — an older C# compiler, F# if it weren't updated to understand the attribute, etc. — would not have a way to resolve the ambiguity in such a case.

@jaredpar
Copy link
Member

jaredpar commented Jul 9, 2024

dotnet/csharplang#7906: developers can add weight to which methods are better in overload resolution. This seems unlikely to impact F# as much.

Want to point out one place this will intersect with F#. Consider that very likely Debug will end up looking like the following:

public static class Debug
{
  [OverloadResolutionPriority(-1)]
  public static void Assert(bool condition) { ... } 

  public static void Assert(bool condition, [CallerArgumentExpression] string? message = "") { ... }
}

Nothing will break for F# here when this happens, code will still compile as it used to. The experience for C# though will improve from a lot of Debug.Assert failed messages to the actual expression that passed into the assert. This is one part I thought might be interesting to F# .

@KevinRansom
Copy link
Member

F# 9.0 is now in and locked.
there are two issues that need a little work, we will try to do before 9.0 ship and turn them on.

#17514
#17509

So I am closing this issue. F# 10.0 is a long way off.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compiler-ImportAndInterop import of .NET DLLs and interop
Projects
Archived in project
Development

No branches or pull requests

6 participants