Skip to content

feat(js/ts/python/dart/beam): support System.Array.BinarySearch and ResizeArray.BinarySearch - #5172

Merged
MangelMaxime merged 6 commits into
fable-compiler:mainfrom
leonitousconforti:support-binary-search
Oct 27, 2026
Merged

MangelMaxime merged 6 commits into
fable-compiler:mainfrom
leonitousconforti:support-binary-search

Conversation

@leonitousconforti

Copy link
Copy Markdown
Contributor

Adds System.Array.BinarySearch and ResizeArray.BinarySearch to JS/TS, Python, Dart and Beam (Rust already has them and is unchanged). One commit per target. It doesn't depend on #5153 or #5154.

Overloads: System.Array.BinarySearch(array, value), (array, value, comparer), (array, index, length, value) and (array, index, length, value, comparer); xs.BinarySearch(item), (item, comparer) and (index, count, item, comparer).

  • The search uses .NET's loop (same midpoint, Compare(element, value) with the element first, complement of the insertion point on a miss), so arrays with duplicates and comparers with side effects give .NET's results.
  • The range overloads check the index, then the length (count for ResizeArray), then the range, raising ArgumentOutOfRangeException or ArgumentException like .NET.
  • Without a comparer, or with a literal null one, the search uses the comparer Fable already sorts with on that target. On Beam that's the one Array.sortInPlace uses, since ResizeArray.Sort() there orders union cases by name.
  • Library functions: binarySearch, binarySearchRange and binarySearchRangeCount in Array.fs (JS/TS, Dart), and the same in snake_case in resize_array.py (Python) and fable_resize_array.erl (Beam). The Python ones live in resize_array.py because they only need len() and indexing, so they serve lists and the Rust-backed arrays alike, and putting them in array_.py would create an import cycle with system. binarySearchRangeCount only exists because .NET names ResizeArray's count count, not length.

Differences from .NET: strings compare ordinally (Comparer<string>.Default is culture-aware), a comparer that's only null at runtime isn't replaced by the default, and an exception from the comparer isn't wrapped in InvalidOperationException (as with Fable's sorts). The non-generic System.Array overloads reach the same code on JS/TS, Python and Dart but aren't tested; on Beam they stay unsupported.

The tests use the same cases and .NET-checked values on every target. Dart and Beam use small comparer classes or object expressions, since Comparer<int>.Default and ComparisonIdentity.FromFunction aren't supported there. The full CI passes on my fork: https://github.com/leonitousconforti/Fable/actions/runs/40390993903

leonitousconforti and others added 6 commits October 26, 2026 14:54
…Search

Map the System.Array and ResizeArray BinarySearch overloads to new
Array.binarySearch, binarySearchRange and binarySearchRangeCount library
functions. The search follows .NET's probe order, the range overloads
raise ArgumentOutOfRangeException and ArgumentException like .NET, and a
missing or null comparer becomes the default comparer that
ResizeArray.Sort() uses.
…ySearch

Both use .NET's search loop, so arrays with duplicates and comparers that
record their calls give .NET's answers. The range overloads check their
arguments like .NET, raising ArgumentOutOfRangeException for a negative
index or length (count for ResizeArray) and ArgumentException for a range
past the end.

The search lives in resize_array.py and only uses len() and indexing, so
it serves Python lists and the Rust-backed arrays alike. An omitted or
null comparer is the default comparer Fable passes to Array.sortInPlace.
…earch

Adds binarySearch and binarySearchRange to the Dart Array library,
following .NET's probe order so arrays with duplicates and custom
comparers give the same results. The range overloads raise
ArgumentOutOfRangeException and ArgumentException like .NET, with
binarySearchRangeCount naming the count "count" for
ResizeArray.BinarySearch(index, count, item, comparer).

Overloads without a comparer, or with a null literal, use the default
comparer that ResizeArray.Sort() uses.
…earch

Both go to new fable_resize_array functions (binary_search,
binary_search_range and binary_search_range_count), which search the
list as a tuple in .NET's probe order after .NET's range checks. A
missing or literal null comparer becomes the comparer Fable uses for
compare, so unions follow declaration order. The non-generic
System.Array overloads stay unsupported.
@MangelMaxime

Copy link
Copy Markdown
Member

Thank you

@MangelMaxime
MangelMaxime merged commit d332e7d into fable-compiler:main Oct 27, 2026
36 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants