Repro steps
Create 1.fsx:
[1..2]
|> Seq.take 3
|> printfn "%A"
printfn "done"
Invoke as:
fsi 1.fsx
Output:
Error: tried to take The input sequence has an insufficient number of elements. 2 past the end of the seq
done
Actual behavior
(1) The error message is formatted in a strange way.
(2) The message appears to be incorrect, we have 1 extra item, not 2.
(3) The error (exception?) does not stop the execution, see "done" printed.
Expected behavior
The expected behavior is similar to List.take and Array.take.
Most importantly, the exception should terminate the execution.
List.take version:
[1..2]
|> List.take 3
|> printfn "%A"
printfn "done"
System.InvalidOperationException: The input sequence has an insufficient number of elements.
The list was 1 element shorter than the index
at ...
Stopped due to error
md5-850c430a532564dbc973f4bed29bd82c
System.InvalidOperationException: The input sequence has an insufficient number of elements.
at ...
Stopped due to error
```
Also note no information on the exceeding element count, unlike in Seq.take and List.take.
Ideally, all 3 Seq.take, List.take, and Array.take should have similar error messages.
Known workarounds
None.
Related information
fsi.exe of Visual Studio 2019 (16.6.2)Interestingly enough, in my testing, Seq.take always reports that it is 2 past the end no matter how far past the end it actually is. Including when using 100.
[1..2]
|> Seq.take 100
|> printfn "%A"
Error: tried to take The input sequence has an insufficient number of elements. 2 past the end of the seq
@TheJayMann Yes, same here. Thank you for the useful detail.
I figured I'd take it a little further.
[1..3]
|> Seq.take 100
|> printfn "%A"
Error: tried to take The input sequence has an insufficient number of elements. 3 past the end of the seq
It appears that a wrong value is being used.
The code is just wrong, it should be keeping track of an index and reporting that back here: https://github.com/dotnet/fsharp/blob/master/src/fsharp/FSharp.Core/seq.fs#L687
Why it doesn't immediately stop due to invalidOp is a different question though. Other exception-producing Seq code (like taking Seq.head on an empty sequence) doesn't continue the script.
From what I can tell, it is stopping at invalidOptFmt. The line afterwards is just a continuation of the function call. Rather, the issue appears to be that it is attempting to report how far beyond the end was requested, but instead reports x, which is just a count of how far into the sequence has been progressed. I believe the line should be changed from [|SR.GetString SR.notEnoughElements; x; (if x = 1 then "element" else "elements")|] to let x = count - x in [|SR.GetString SR.notEnoughElements; x; (if x = 1 then "element" else "elements")|]
Yes the error is here:
invalidOpFmt "tried to take {0} {1} past the end of the seq"
[|SR.GetString SR.notEnoughElements; x; (if x = 1 then "element" else "elements")|]
I believe this should be
invalidOpFmt "{0}: tried to take {1} {2} past the end of the seq"
[|SR.GetString SR.notEnoughElements; x; (if x = 1 then "element" else "elements")|]
There are several occurrences of this
I'd also add a hint to this exception message. Smth like Consider Seq.truncate, if you wanted no more than n elements.