Changelog
View Sourcev2.0.0 (2026-10-02)
This release contains breaking changes, see the upgrade guide for how to migrate.
Breaking changes
- Changed
Accessto consider that an index exists when it is within the bounds of the array (0 <= index < size/1), whatever the value of its entry, instead of treating entries holding the default value as missing.arr[index]now always returns the same value asget/2for indexes in bounds, including when the default value is notnil.Access.fetch/2returns{:ok, value}for every index in bounds, including entries holding the default value, and:errorfor any other index (out of bounds, negative or not an integer) instead of raising anArgumentError.Access.pop/2resets the entry and returns its value for every index in bounds, and returns{nil, array}for any other index instead of raising anArgumentError.Access.get_and_update/3passesnilto the function for indexes out of bounds. Updating such an index grows an extendible array and raises anArgumentErrorfor a fixed-size array, as before.
- Removed
is_array/1andis_fix/1, replaced byarray?/1andfixed?/1to follow the Elixir convention of reserving theis_prefix for guards. - Changed
equal?/2to also compare the size, the default value and the fixedness of the arrays. Previously, arrays with different default values or fixedness were considered equal when their entries were the same. - Changed
Collectable.into/1to raise anArgumentErrorwith an explanatory message as soon as an element is collected into a fixed-size array, instead of the bareArgumentErrorraised by:array.set/3.
Features
- Added
array?/1andfixed?/1. - Added support for a single non-list option in
new/1, such asnew(:fixed)ornew({:default, 0}), as allowed by theoptions()type and the documentation. It used to raise aFunctionClauseError.
Bug fixes
- Fixed
Access.get_and_update/3raising aMatchErrorwhen the function returns:pop. The entry is now reset to the default value and its previous value returned, asAccess.pop/2does. - Fixed
Inspectignoring the inspect options (e.g.:syntax_colors) when rendering the default value.
Performance
- Improved
Enumerable.reduce/3to stop converting the whole array to a list before reducing. The first elements are visited by index, so reductions that halt early (Enum.take/2,Enum.find/2,Enum.any?/2, ...) run in constant time and memory instead of O(n): on a 1,000,000-element array,Enum.take(arr, 10)drops from ~7 ms to under 1 µs and from ~15 MB to under 1 KB of memory. Full traversals keep the speed of the list-based implementation. - Improved
Inspectto only materialize the elements that will be printed (honoring the:limitoption), instead of converting the whole array to a list: inspecting a 1,000,000-element array drops from ~9 ms to ~26 µs. - Improved
Collectable.into/1when collecting into an empty extendible array: the values are accumulated and the array is built at once with:array.from_list/2, which is 3 to 5 times faster than setting them one by one. - Simplified
Enumerable.slice/1to always return the 3-arityslicing_fun, which is supported since Elixir 1.14, removing the compile-time Elixir version check.
Documentation
- Fixed the documentation of
map/2,sparse_map/2,foldl/3,sparse_foldl/3,foldr/3andsparse_foldr/3, which raise aFunctionClauseError(not anArgumentError) whenfunis not a function of the expected arity, and ofget/2, which returns the default value for indexes out of bounds of extendible arrays. - Fixed the README description of
AccessandCollectable, and added doctests for the documentation examples. - Added an upgrade guide.
- Added a section to the README explaining when to use
ExArrayinstead of aList, a tuple or a map.
Internal
- Added
bench/run.exsandbench/compare.shto benchmark the protocol andAccessimplementations (run time, memory usage and reductions) with Benchee, and compare a git revision against the working tree. - Added regression tests for the changes above and for halting and
suspending reductions (
Enum.zip/2,Stream.zip/2) on small and large arrays. - Fixed the type warnings emitted by the test suite on Elixir v1.18+, and a
set/3test that was callingget/2. - Silenced the ExDoc warnings about functions referenced by past releases in the changelog.
v1.0.0 (2026-06-16)
- Fixed
Access.fetch/2andAccess.pop/2to no longer treat stored falsy values (e.g.false,nil) as missing; entries are now compared against the array's default value instead of a truthy check. - Improved
Collectable.into/1to append via:array.set/3starting at the original array'ssize/1, instead of rebuilding throughto_list/from_list. The original array'sdefaultandfixedattributes are now preserved. - Improved
Enumerable.slice/1to return aslicing_fun, so partial slices touch only the requested window rather than materializing the full list. The implementation is selected at compile time: the 2-arity form on Elixir 1.14–1.17, and the 3-arity form (withstepsupport) on Elixir 1.18+, which silences the deprecation warning emitted on those versions. - Replaced the soft-deprecated
unlessmacro infrom_erlang_array/1for forward compatibility with Elixir 1.19+. - Fixed typespecs so
mix dialyzerpasses on Elixir 1.18 / OTP 28+. The hand-writtenarray()opaque tuple now delegates to:array.array/0, andorddict()is exposed as a regular@type(it is a user-constructable list of{index, value}tuples, not an opaque value). - Added a GitHub Actions workflow exercising
mix compile --warnings-as-errors,mix test, andmix dialyzeracross every supported Elixir 1.14–1.20 / OTP 24–29 combination. - Documented the
Access,Enumerable, andCollectableprotocols in the README, added examples for the remaining public API, and fixed a stale output value and a typo (Convertions→Conversions). - Added regression tests covering the
Accessfalsy-value fix,Collectableattribute preservation, theEnum.slice/3start/lengthform, and stepped ranges (Enum.slice(arr, 0..5//2)) to exercise the 3-arityslicing_fun's step path on Elixir 1.18+.
v0.1.3 (2023-04-21)
- Improved the README.md by providing examples
v0.1.2 (2023-04-21)
- Added tests to get full coverage
- Replaced the implementation of
ExArray.equal?/2 - Added a clause for non
ExArrayargument forExArray.is_array/1 - Fixed the implementation of
ExArray.from_erlang_array/1to return anExArray
v0.1.1 (2023-04-21)
- Changed the internal implementation of
ExArray - Improved the typespecs and documentations
v0.1.0 (2023-04-20)
- Version initial