[main] Source code updates from dotnet/runtime#2627
[main] Source code updates from dotnet/runtime#2627dotnet-maestro[bot] merged 13 commits intomainfrom
Conversation
|
Important The source repository has received code changes from an opposite flow. Any additional codeflows into this PR may potentially result in lost changes.
In case of unclarities, consult the FAQ or tag @dotnet/product-construction for assistance. |
|
|
this is caused by the Rune changes from dotnet/runtime#120145 |
|
|
The code in the F# compiler can be annotated to choose the right overload, but the code has nothing "special" about it - similar calling patterns will for sure exist at other F# programs. Meaning this will break user code equally well. It is a a source-breaking change for languages that are in the business of any non-trivial type inference. Thinking out loud: type String with
member inline x.StartsWithOrdinal value =
x.StartsWith(value, StringComparison.Ordinal)
member inline x.EndsWithOrdinal value =
x.EndsWith(value, StringComparison.Ordinal)
member inline x.EndsWithOrdinalIgnoreCase value =
x.EndsWith(value, StringComparison.OrdinalIgnoreCase)
|
|
@akoeplinger : Orthogonal to the message above, can I make the code change for fsharp compiler's own usage here in this PR directly ,, to stop blocking dotnet/runtime forward flow? Since this is main, it is for the NET11 period already, right? |
|
yes it is for net11 and you can make the change here but as you said it'll break user code as well so I'm not sure if it's the right course of action. |
|
The only other quick option is to revert the PR that introduced these APIs. There are likely going to be more build breaks in F# code in other repos once the new APIs starts propagating through the system (e.g. in test code that does not build in dotnet/dotnet). I am not able to predict how bad it is going to be. @T-Gro Your call whether to fix the F# compiler here and allow the new APIs to propagate, or whether you would like to see the new APIs reverted until this is discussed. |
Hello, I am not understanding what has been broken here. Have I done something wrong in my pull request? Why doesn't it work in F#? |
The reason is that w.r.t. to type inference (no need to manually annotate types of values, return values, arguments etc.), the change of going from 1 method overload with the same amount of parameters to 2+ method overloads is a source-breaking-change. |
I am afraid that if we let it in now, there will be no reason to push the discussion further and decrease the chances of changing the design. I would personally be in favor of:
One reason is the source-breaking-change for inferred argument types, the other would be from a code organization philosophy - extensions are a tool to avoid putting hundreds of methods into a few "master classes". |
We prefer instance methods over extension methods when designing new APIs. We are perfectly fine with a lot of methods on a class. This is mentioned in .NET Framework design guidelines (you can checkout e-book in ms library): AVOID frivolously defining extension methods, especially on types outside your library or framework. Introducing this as an extension would be controversial. |
|
Does the issue is with |
I am wondering if this can happen most of the time by adding overloads with the same number of parameters. I don't think we should be restricting adding the right form of overloads because of that. |
|
It's certainly a thing we can discuss... Off the top of my head:
So it'll sort of come down to "is this going to break 'everyone' who uses F#?". If it requires two...four...twenty things to align, then we might say to break them. If
Jan already quoted one of the guidelines, but the gist is "nothing should be an extension method unless there's a good reason". (e.g. "One of the arguments is defined in a later assembly", "It's a method on a generic type that's popular with value types and it won't be used for most "We think the method is important, but it's too-breaking for F#, and there's no other way" might be a reason. But we definitely don't start there. |
|
@T-Gro to unblock this PR, could you please fix this in the F# side and open issue to track discussing this further? I can open the issue if you like too. |
You can see the added APIs list here dotnet/runtime#27912 (comment). Considering the changes are in String class, the change may break many users, but it depends on what API they are calling. I guess many F# users can be affected but source change should be simple and few (depending on the code). Now, to unblock this PR, what do you think? Revert the changes in the runtime till we decide? or fix the F# failure here? We'll discuss how to fix this either way later. |
|
I don't really have enough information/knowledge to make a recommendation. I see 4 errors reported. If they're the only four, that looks like "maybe not a giant break". If they're just the first four, and things stopped building, then maybe it's a giant break. The first three look like some form of local function definition. Is that common? Is that canonically written? I don't use F#, so I don't know. The fourth one looks like it's in (what in C# would be) a lambda-like context. Is that code canonical? If so, maybe it's going to be a massive break. Or maybe this is the only line of code in the whole world combining tryFindIndexBack with string.StartsWith. The only reasonable advice I can give is that seeing what change would be required to just push this through is useful data (if it's small, maybe we take the break-risk / if it's large, maybe we do something else / if it's medium we get to go "hmmm" a lot). |
|
My understanding of the four failures is that they occur because the code uses StartsWith and EndsWith, for which we recently added overloads with the same number of parameters. If there are users calling other APIs (e.g., IndexOf) where we’ve also added overloads with the same parameter count as existing ones, I would expect similar failures there as well. I’m not an expert in F#, so @T-Gro may be able to provide more insight. The list of APIs we added is here dotnet/runtime#27912 (comment) |
|
In general, this source breaking change happens when:
Indeed, this might have affected more APIs from the same PR. The change is not source breaking for F# if the value's type has been already inferred to be That being said, not manually annotating types is the idiomatic programming style for F#(i.e. not something hypothetical): member inline x.StartsWithOrdinal value =
x.StartsWith(value, StringComparison.Ordinal)You mentioned (the big "if" comes around the usage of it) |
|
Just to make it super clear - my position for sure isn't saying no to But unless Runes are meant to become "the new char", I still see value in detaching them from the most common type in .NET and only showing/exposing them to users who seek them. Just like Regex search not being directly defined on If I am wrong and Runes are meant to be used by most .NET programmers, let's just accept this and F# programs will get a compiler diagnostic forcing them to choose once they update their framework. |
We’re adding these |
Please note that the changes are not solely related to Console.WriteLine("HELLO".StartsWith('h', StringComparison.OrdinalIgnoreCase)); // new overload that returns TruePreviously, you could only pass a Console.WriteLine("HELLO".StartsWith("h", StringComparison.OrdinalIgnoreCase)); // TrueThis addition makes it consistent with methods like Console.WriteLine("HELLO".Contains('h', StringComparison.OrdinalIgnoreCase)); // True |
Yes, that is the same category here.
If the goal was to treat it on-par witch char and flow it trough many levels of APIs, I wonder if there isn't a missing generalization, just there used to be a missing one for "generic math". If the type system could express the semantic intention of "all search APIs accept a 'T which is a string OR char OR Rune", it would generalize well, work with type inference and would not cause a source-breaking change for F# programs. I do realize this might be a non-goal, but it would also reduce the need for multiplying overloads across method calls that end up calling the same underlying helper. |
|
This is blocking the codeflow for too long. @T-Gro Could you please add commit to this PR to make the FSharp compiler build to unblock this?
I do not think so. It is super common to overload APIs like this without any generalizations. From API design guidelines:
|
Note
This is a codeflow update. It may contain both source code changes from the source repo as well as dependency updates. Learn more here.
This pull request brings the following source code changes
From https://github.com/dotnet/runtime