RFC FS-1033: Deprecate places where `seq` can be omitted
Description
Implements https://github.com/fsharp/fslang-suggestions/issues/1033
Deprecate { start..finish } and { start..step..finish }
Before
To create a sequence, you can use { start..finish } or { start..finish..step }.
{ 1..10 }
{ 1..5..10 }
[| { 1..10 } |]
[| { 1..5..10 } |]
[| yield { 1..10 } |]
[ { 1..10 } ]
[ { 1..10..10 } ]
[ yield { 1..10 } ]
[ yield { 1..10..20 } ]
ResizeArray({ 1..10 })
ResizeArray({ 1..10..20 })
[ for x in { start..finish } -> x ]
[| for x in { start..finish } -> x |]
for x in { 1..10 } do ()
for x in { 1..5..10 } do ()
set { 1..6 }
Seq.length { 1..8 }
Seq.map3 funcInt { 1..8 } { 2..9 } { 3..10 }
Seq.splitInto 4 { 1..5 } |> verify { 1.. 10 }
seq [ {1..4}; {5..7}; {8..10} ]
Seq.allPairs { 1..7 } Seq.empty
Seq.allPairs Seq.empty { 1..7 }
[| yield! {1..100}
yield! {1..100} |]
After
A new warning will be raised when using { start..finish } or { start..finish..step } to create a sequence.
{ 1..10 } // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
{ 1..5..10 } // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
[| { 1..10 } |] // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
[| { 1..5..10 } |] // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
[| yield { 1..10 } |] // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
[ { 1..10 } ] // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
[ { 1..10..10 } ] // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
[ yield { 1..10 } ] // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
[ yield { 1..10..20 } ] // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
ResizeArray({ 1..10 }) // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
ResizeArray({ 1..10..20 }) // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
[ for x in { start..finish } -> x ] // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
[| for x in { start..finish } -> x |] // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
for x in { 1..10 } do () // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
for x in { 1..5..10 } do () // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
set { 1..6 } // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
Seq.length { 1..8 } // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
Seq.map3 funcInt { 1..8 } { 2..9 } { 3..10 } // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
Seq.splitInto 4 { 1..5 } |> verify { 1.. 10 } // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
seq [ {1..4}; {5..7}; {8..10} ] // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
Seq.allPairs { 1..7 } Seq.empty // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
Seq.allPairs Seq.empty { 1..7 } // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
[| yield! {1..100} // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
yield! {1..100} |] // FS3873, "This construct is deprecated. Sequence expressions should be of the form seq {...}"
To create a sequence, you need to use seq { start..finish } or seq { start..finish..step }.
seq { 1..10 }
seq { 1..5..10 }
[| seq { 1..10 } |]
[| seq { 1..5..10 } |]
[| yield seq { 1..10 } |]
[ seq { 1..10 } ]
[ seq { 1..10..10 } ]
[ yield seq { 1..10 } ]
[ yield seq { 1..10..20 } ]
ResizeArray(seq { 1..10 })
ResizeArray(seq { 1..10..20 })
[ for x in seq { start..finish } -> x ]
[| for x in seq { start..finish } -> x |]
for x in seq { 1..10 } do ()
for x in seq { 1..5..10 } do ()
set { 1..6 }
Seq.length (seq { 1..8 })
Seq.map3 funcInt (seq { 1..8 }) (seq { 2..9 }) (seq { 3..10 })
Seq.splitInto 4 (seq { 1..5 }) |> verify (seq { 1.. 10 })
seq [ seq {1..4}; seq {5..7}; seq {8..10} ]
Seq.allPairs (seq { 1..7 }) Seq.empty
Seq.allPairs Seq.empty (seq { 1..7 })
[| yield! seq {1..100}
yield! seq {1..100} |]
Checklist
- [x] RFC https://github.com/fsharp/fslang-design/pull/788
- [x] Test cases added
- [x] QuickFix add
AddMissingSeqThanks to Brian - [x] Release notes entry updated
:heavy_exclamation_mark: Release notes required
:white_check_mark: Found changes and release notes in following paths:
Change path Release notes path Description src/Compilerdocs/release-notes/.FSharp.Compiler.Service/9.0.200.md LanguageFeatures.fsidocs/release-notes/.Language/preview.md vsintegration/srcdocs/release-notes/.VisualStudio/17.13.md
I am not 100% sure what exactly was approved in the comment, but I don't immediately see it as "let's allow omitting seq for those cases everywhere. It is taking about when we pass it to collections.
I am not 100% sure what exactly was approved in the comment, but I don't immediately see it as "let's allow omitting
seqfor those cases everywhere. It is taking about when we pass it to collections.
@vzarytovskii what I understood from Don’s comment was that we want to enforce the seq in places where we pass it to collections via a warning or informational warning.
To do this we need to have valid code for { 1;10} to show such a warning right(We do not show warnings on invalid code AFIK) ?
Also note that { 1..10 } is currently valid currently. So { 1;10} arguable should also be.
To summarise my current approach is:
- Make
{1;10}valid code for consistency - Add a warning to force the use of
seqwhen passing it to collections.
I am not 100% sure what exactly was approved in the comment, but I don't immediately see it as "let's allow omitting
seqfor those cases everywhere. It is taking about when we pass it to collections.@vzarytovskii what I understood from Don’s comment was that we want to enforce the
seqin places where we pass it to collections via a warning or informational warning.To do this we need to have valid code for
{ 1;10}to show such a warning right(We do not show warnings on invalid code AFIK) ?Also note that
{ 1..10 }is currently valid currently. So{ 1;10}arguable should also be.To summarise my current approach is:
Make
{1;10}valid code for consistencyAdd a warning to force the use of
seqwhen passing it to collections.
Hm, I've read it a bit differently -
That is, if the seq is being immediately consumed eagerly into a collection construction then I'm happy to omit it.
I read it as - when we immediately pass it to collections, then we do not require "seq" (even for now illegal constructs), otherwise (if not passed to collections) we add a warning enforcing (suggesting really) to add "seq" to "{ x .. y }".
But I have problems decoding the comment w.r.t. allowing other constructs to omit "seq" when not passed to collections (when returning or binding for example.
But I have problems decoding the comment w.r.t. allowing other constructs to omit "seq" when not passed to collections (when returning or binding for example.
what about let x = { 1..10 } should this now be disallowed by a warning. I’m trying to understand the rationale about the existing inconsistency between both cases in bindings ?
But I have problems decoding the comment w.r.t. allowing other constructs to omit "seq" when not passed to collections (when returning or binding for example.
what about
let x = { 1..10 }should this now be disallowed by a warning. I’m trying to understand the rationale about the existing inconsistency between both cases in bindings ?
That's what I understood. Show a diagnostic suggesting adding "seq" if it's not passed to collection. And allow other constructs only when passed to collections.
I'd wait for other folks to read it through, I might be misunderstanding things.
I like the uniformity of us forcing to use seq in all places, but fixing exiting code might be tedious, yes.
@T-Gro @vzarytovskii Yeah a code fix is also part of my plan.
As thing stand today we need to implement for each editor. I can do the VSCode and and maybe Rider if the F# team does the VS one.
I know this has been approved, but I do not like the impact this has on the regular FSharp user.
Yeah it is approved. But if the F# team disagrees I please encourage to go through the lang suggestions and reject these or clarifies the state.
Im happy to work together to get this through if that is really the intention.
If the codefix will come within the same release window, all is good - I am approving.
@T-Gro @psfinaki Is the expectation for the quick fix to be implemented as part of this PR of should we create a issue for it after this PR is merged.
Thanks @brianrourkeboll for the quick fix.
Alrighty, brilliant job @brianrourkeboll also. Let's merge this all in :) Thanks both!
Thanks @brianrourkeboll , @edgarfgp . Last step for this "chapter" would be to also apply it in this very codebase (assuming there is at least 1 occurrence that needs fixing), so that we do not get immediate warnings when the SDK is updated to have this warning 👍 .
(I assume the codefix should work in bulk mode, right?)
@T-Gro
Last step for this "chapter" would be to also apply it in this very codebase (assuming there is at least 1 occurrence that needs fixing).
It is already done. As part of this PR update all the instances mostly testing code.
I assume the codefix should work in bulk mode, right?
Not sure why would not. But I do not have a Windows machine try this. But I assume there is a way to write a unit tests for this.
@edgarfgp good, I was afraid there might be more :).
It is a bulk fix, as per the code fix code, should be good :)
(I assume the codefix should work in bulk mode, right?)
Yes, although with the same limitations that (as far as I know) apply to all current F# code fixes: #16999 and the inability to handle nested instances of the same fix.
https://github.com/user-attachments/assets/93e25b8c-6619-427c-800b-7de5518aa91e