Repository navigation
fix(js/ts/python/dart/beam): add FSharp.Core's argument checks to collection functions - #5154
Merged
MangelMaxime merged 5 commits intoOct 28, 2026
Conversation
Contributor
Author
|
I am rebasing this |
leonitousconforti
force-pushed
the
fix-missing-collection-checks
branch
2 times, most recently
from
October 27, 2026 13:59
0575155 to
b5a7838
Compare
This was referenced Oct 27, 2026
fix(js/ts/python/dart/rust/beam): use FSharp.Core's algorithms for random collection functions
#5197
Merged
Collection functions that FSharp.Core rejects arguments for returned a value (often a wrong one), and a few raised where FSharp.Core does not. They now behave like FSharp.Core, raising its exception types with its ParamNames: - List.fold2, map2, mapi2, map3, zip, zip3, iter2, iteri2 and forall2 raise ArgumentException for lists of different lengths, after calling the function on the common items. forall2 still stops at the first false. List.foldBack2 names the lists like FSharp.Core, and List.exists2 now gives the same "The lists had different lengths." message as the others. - List.init, List.replicate, Seq.init and Seq.take raise ArgumentException for negative counts, Seq.replicate ArgumentOutOfRangeException. The Seq functions check when called, like Seq.chunkBySize, Seq.windowed and Seq.splitInto now do. - List.average and List.averageBy raise ArgumentException on empty lists. - Array.sub and Array.fill check their ranges. Array.blit and System.Array.Copy, which now compiles to Array.copyTo instead of Util.copyToArray, raise System.Array.Copy's exceptions and leave the target untouched. The Int64 overloads of System.Array.Copy convert their arguments (they failed before), and a copy within one array handles overlapping ranges like System.Array.Copy. - List, Array and Seq.removeManyAt raise ArgumentException when FSharp.Core does, and a count of 0 removes nothing. A negative count removes nothing from an array, where FSharp.Core gives odd results. - Seq.transpose groups jagged input by index like FSharp.Core instead of raising. Array.transpose and List.transpose still raise. - Array.chunkBySize and Array.splitInto (and so List's) use FSharp.Core's ParamNames.
Several List and Seq functions returned a value, often a wrong one, where FSharp.Core rejects the argument, and a few raised where FSharp.Core does not. They now behave like FSharp.Core: - List.fold2, map2, mapi2, map3, zip, zip3, iter2, iteri2 and forall2 raise ArgumentException when the lists have different lengths, after calling back on the common prefix. forall2 still stops at the first false. List.foldBack2, which raised the Rust core's ValueError, checks the lengths before calling back. Every List length check, exists2's included, now uses FSharp.Core's message. - List.init, List.replicate, Seq.init and Seq.take raise ArgumentException for a negative count, Seq.replicate ArgumentOutOfRangeException. The Seq checks run when the function is called. - List.average and List.averageBy raise ArgumentException on an empty list. - List.removeManyAt raises exactly when FSharp.Core does and removes nothing for a count <= 0. Seq.removeManyAt raises after enumeration only when the source is too short for index, and no longer when the count runs past the end. Both use FSharp.Core's messages. - Seq.chunkBySize, Seq.windowed and Seq.splitInto check the size when called, with FSharp.Core's parameter names. - Seq.transpose groups jagged input by index like FSharp.Core instead of raising through Array.transpose.
Collection functions returned a value, often a wrong one, where FSharp.Core rejects the arguments, and a few raised where FSharp.Core does not. They now follow FSharp.Core, with its exception types and ParamNames: - List.fold2, map2, mapi2, map3, zip, zip3, iter2, iteri2 and forall2 raise ArgumentException when the lists have different lengths, after calling the function on the common prefix. forall2 still returns false before reaching the end. List.foldBack2 names the lists like FSharp.Core, and every List length check says "The lists had different lengths.". - List.init and List.replicate with a negative count, and List.average and List.averageBy on an empty list, raise ArgumentException. - Seq.init, Seq.take, Seq.chunkBySize, Seq.windowed and Seq.splitInto check their argument when called, and Seq.replicate raises ArgumentOutOfRangeException, instead of returning an empty sequence or failing on enumeration. Array.chunkBySize and Array.splitInto use FSharp.Core's ParamNames. - Array.sub, Array.fill, Array.blit and System.Array.Copy check their indexes and counts up front, and Array.fill allows a count of 0 past the end. Array.sub gets its own library function so ResizeArray.GetRange keeps using getSubArray. - List, Array and Seq.removeManyAt raise ArgumentException with FSharp.Core's messages when FSharp.Core does (Seq also when the sequence is not longer than index), and a count of 0 or less removes nothing (on arrays FSharp.Core copies odd ranges or fails in System.Array.Copy). Seq.removeManyAt allows a count past the end. - Seq.transpose groups the elements by index like FSharp.Core instead of raising for sequences of different lengths.
Some collection functions returned a value (often a wrong one), looped forever or failed with an untyped Erlang error where FSharp.Core rejects the argument, and a few raised where FSharp.Core does not: - Array.sub raises ArgumentException for a negative startIndex or count and ArgumentOutOfRangeException for a range past the end, instead of truncating through lists:sublist/3. It still walks only the items it needs. - Array.blit checks its arguments like System.Array.Copy, in the same order, before it copies anything. A source range past the end shortened the target instead of raising ArgumentException. - Seq.init and Seq.take raise ArgumentException, and Seq.replicate ArgumentOutOfRangeException (it is Enumerable.Repeat on .NET), for a negative count when they are called. They returned an empty sequence. - List, Array and Seq chunkBySize, windowed and splitInto reject a size below 1 with FSharp.Core's parameter names, the Seq ones when they are called. chunkBySize 0 looped forever, and so did splitInto with some negative counts. - splitInto returns an empty result for an empty input instead of dividing by zero. - List.transpose and Array.transpose raise ArgumentException for jagged input instead of truncating it or failing in hd/1. Seq.transpose groups jagged input by index like FSharp.Core instead of going through Array.transpose. - List.forall2 and List.exists2 walk both lists like FSharp.Core instead of zipping them first, so they return as soon as the predicate decides and raise ArgumentException only when one list runs out first. Array.forall2 and Array.exists2 check the lengths up front. - Seq.removeManyAt follows FSharp.Core: a count past the end or below 1 is not an error, and a source without an element at index raises ArgumentException once it has been enumerated. The 3-argument System.Array.Copy, which ignores its destination, is a different bug and is left alone.
MangelMaxime
force-pushed
the
fix-missing-collection-checks
branch
from
October 28, 2026 19:40
b5a7838 to
ce0ad52
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #5153. One commit per target.
Several List, Array and Seq functions returned a value, often a wrong one, where FSharp.Core rejects the argument. This adds FSharp.Core's checks, with its exception types and parameter names:
List.fold2,map2,mapi2,map3,zip,zip3,iter2,iteri2andforall2raiseArgumentExceptionfor lists of different lengths instead of truncating. As in FSharp.Core, the callback still runs on the common prefix andforall2/exists2still stop early. Code that relied on the truncation will now throw, so I can split this part out if you'd rather ship it separately.List.init/replicateandSeq.init/takeraiseArgumentException,Seq.replicateraisesArgumentOutOfRangeException. The Seq ones, likeSeq.chunkBySize/windowed/splitInto, now check when called rather than when enumerated.List.average/averageByon an empty list (returned NaN).Array.sub,Array.fill,Array.blitandSystem.Array.Copyout of range (clamped, wrote past the end, or threw a native error).List/Array/Seq.removeManyAtraise exactly when FSharp.Core does. A count of 0 used to remove an item.Seq.transposeaccepts jagged input like FSharp.Core (it groups by index) instead of raising.Notes:
System.Array.Copycompiles to the checkedArray.copyToinstead ofUtil.copyToArray. TheInt64overloads convert their arguments, which also makes them work, and ablitwithin one array now copies overlapping ranges correctly.Array.sub/fill/blitget the same checks as JS (they threw a nativeRangeError).Seq.fs, plus Erlang functions that returned a value, looped or raised where .NET doesn't:chunkBySize 0looped forever,transposetruncated jagged lists,Array.subandArray.blitpast the end truncated,forall2/exists2couldn't stop early, andsplitIntoon an empty list divided by zero. Functions that already fail with a native Erlang error (e.g.List.zipwith different lengths) are unchanged.Array.fillchecks before writing (.NET fills up to the end, then raises),Array.removeManyAtwith a negative count removes nothing, and int32 overflow with huge counts isn't emulated.Not covered: null checks, BCL collections (
ResizeArray.CopyTostays unchecked),Array.create/zeroCreatesizes, and Rust.The new tests assert exception types, since Fable code can't read
ParamName.