Skip to content

Let map and broadcast return values of a type without zero - #1055

Merged
ViralBShah merged 2 commits into
mainfrom
vs/map-result-without-zero
Oct 13, 2026
Merged

ViralBShah merged 2 commits into
mainfrom
vs/map-result-without-zero

Conversation

@ViralBShah

@ViralBShah ViralBShah commented Oct 13, 2026 •

Copy link
Copy Markdown
Member

map and broadcast over a sparse array throw a MethodError when the function returns a value of a type that has no zero, such as a String, a Tuple, a Pair or nothing.

using SparseArrays
A = sparse([1.0 0.0; 0.0 2.0])
string.(A)
A .=> 1
map(x -> (x,), A)
map(x -> nothing, A)

Before

string.(A)            MethodError: no method matching zero(::String)
A .=> 1               MethodError: no method matching zero(::Pair{Float64, Int64})
map(x -> (x,), A)     MethodError: no method matching zero(::Tuple{Float64})
map(x -> nothing, A)  MethodError: no method matching zero(::Nothing)

After

string.(A)            ["1.0" "0.0"; "0.0" "2.0"]
A .=> 1               sparse([1, 2, 1, 2], [1, 1, 2, 2], [1.0 => 1, 0.0 => 1, 0.0 => 1, 2.0 => 1], 2, 2)
map(x -> (x,), A)     sparse([1, 2, 1, 2], [1, 1, 2, 2], [(1.0,), (0.0,), (0.0,), (2.0,)], 2, 2)
map(x -> nothing, A)  sparse([1, 2, 1, 2], [1, 1, 2, 2], [nothing, nothing, nothing, nothing], 2, 2)

To choose between the zero-preserving kernel and the one that fills the result, the dispatchers evaluate f at the zeros and call _iszero on the value, which calls zero for anything but a Number. The new _iszeroresult is _iszero for a Number, an AbstractArray or Missing, and for any other value returns false when _iszero throws a MethodError: a value without a zero is not one, and fills the result like any other nonzero. It replaces _iszero wherever f at the zeros is tested: the map! and broadcast! dispatchers, _noshapecheck_map, the zero-argument broadcast!, _diffshape_broadcast and _preserveszeros, where only the call of f stays inside the try. The try is reached only for a non-Number result, so the result types of map(sin, A) and A .+ B are inferred as before.

Left out: a broadcast of two or more arguments where one of them stores every entry, such as string.(A, sparse(ones(2, 2))), still throws MethodError: no method matching zero(::String). That path tests each computed entry for zero, and a tolerant check there would cost every eltype that is not a Number.

Split from #1022.

Written by Claude Code.

🤖 Generated with Claude Code

@codecov

codecov Bot commented Oct 13, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.77%. Comparing base (3d6d696) to head (aee01a1).
⚠️ Report is 5 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #1055   +/-   ##
=======================================
  Coverage   94.77%   94.77%           
=======================================
  Files          16       16           
  Lines        9913     9917    +4     
=======================================
+ Hits         9395     9399    +4     
  Misses        518      518           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

ViralBShah and others added 2 commits October 13, 2026 05:17
Deciding whether `f` preserves zeros called `_iszero(f(0...))`, which throws a
`MethodError` when the value is a `String`, a `Tuple`, a `Pair` or `nothing`.
`_iszeroresult` treats such a value as a nonzero, so it fills the result.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ViralBShah
ViralBShah force-pushed the vs/map-result-without-zero branch from 9f40c9a to aee01a1 Compare October 13, 2026 05:20
@ViralBShah
ViralBShah merged commit 04c122a into main Oct 13, 2026
8 checks passed
@ViralBShah
ViralBShah deleted the vs/map-result-without-zero branch October 13, 2026 05:30

@ViralBShah ViralBShah left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed by Codex at aee01a1.

No actionable findings within the dispatcher changes. Results without a defined zero now reach the fill path while the existing numeric, array and missing-value checks retain their behavior. The fully stored multi-argument limitation is explicitly identified in the PR.

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.

1 participant