fsharp icon indicating copy to clipboard operation
fsharp copied to clipboard

RFC FS-1033: Deprecate places where `seq` can be omitted

Open edgarfgp opened this issue 1 year ago • 11 comments

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 AddMissingSeq Thanks to Brian
  • [x] Release notes entry updated

edgarfgp avatar Sep 20 '24 21:09 edgarfgp

:heavy_exclamation_mark: Release notes required


:white_check_mark: Found changes and release notes in following paths:

Change path Release notes path Description
src/Compiler docs/release-notes/.FSharp.Compiler.Service/9.0.200.md
LanguageFeatures.fsi docs/release-notes/.Language/preview.md
vsintegration/src docs/release-notes/.VisualStudio/17.13.md

github-actions[bot] avatar Sep 20 '24 21:09 github-actions[bot]

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.

vzarytovskii avatar Sep 21 '24 00:09 vzarytovskii

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.

@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 seq when passing it to collections.

edgarfgp avatar Sep 21 '24 07:09 edgarfgp

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.

@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 seq when 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.

vzarytovskii avatar Sep 21 '24 07:09 vzarytovskii

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 ?

edgarfgp avatar Sep 21 '24 07:09 edgarfgp

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.

vzarytovskii avatar Sep 21 '24 08:09 vzarytovskii

I like the uniformity of us forcing to use seq in all places, but fixing exiting code might be tedious, yes.

vzarytovskii avatar Oct 10 '24 09:10 vzarytovskii

@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.

edgarfgp avatar Oct 10 '24 09:10 edgarfgp

If the codefix will come within the same release window, all is good - I am approving.

T-Gro avatar Oct 10 '24 12:10 T-Gro

@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.

edgarfgp avatar Oct 18 '24 16:10 edgarfgp

Thanks @brianrourkeboll for the quick fix.

edgarfgp avatar Oct 19 '24 19:10 edgarfgp

Alrighty, brilliant job @brianrourkeboll also. Let's merge this all in :) Thanks both!

psfinaki avatar Oct 21 '24 10:10 psfinaki

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 avatar Oct 21 '24 10:10 T-Gro

@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 avatar Oct 21 '24 11:10 edgarfgp

@edgarfgp good, I was afraid there might be more :).

T-Gro avatar Oct 21 '24 11:10 T-Gro

It is a bulk fix, as per the code fix code, should be good :)

psfinaki avatar Oct 21 '24 11:10 psfinaki

(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

brianrourkeboll avatar Oct 21 '24 12:10 brianrourkeboll