In short
julia> "Julia" == 0
false
but
julia> iszero("Julia")
ERROR: MethodError: no method matching zero(::String)
Closest candidates are:
zero(::Type{Base.LibGit2.GitHash}) at libgit2/oid.jl:106
zero(::Type{Base.Pkg.Resolve.VersionWeights.VWPreBuildItem}) at pkg/resolve/versionweight.jl:82
zero(::Type{Base.Pkg.Resolve.VersionWeights.VWPreBuild}) at pkg/resolve/versionweight.jl:124
...
Stacktrace:
[1] iszero(::String) at ./number.jl:22
But String is relatively arbitrarily chosen here. An implication of this is that
julia> countnz([:Julia])
1
julia> countnz([[0.0]])
1
julia> !iszero([0.0])
false
because countnz tests with x != 0. It could also test with !iszero but then countnz([:Julia]) would fail.
This came up in https://github.com/JuliaLang/julia/pull/22945 but is kind of separate from the PR so I think it deserves its own issue. There was a previous discussion of this issue in https://github.com/JuliaLang/julia/pull/17623#discussion_r92877227 but I'm not sure how many people noticed.
Possible solutions I can come up with are
iszero(x) = false and use !iszero whenever testing for zero in e.g. countnz and find. This would make countnz([[0.0]]) == 0 and countnz([:Julia]) == 1== method or make it try to convert the arguments to the same type and use !iszero in countnz and find. This would make countnz([[0.0]]) == 0 and countnz([:julia]) fail, but probably also make a million other things throw.iszero and == as they are but use !iszero in countnz and find. This would make countnz([[0.0]]) == 0 and countnz([:julia]) fail.countnz([[0.0]]) == 1 (which I think is the wrong result) and countnz([:Julia]) == 1Update: I think we should add this to the milestone for 1.0.
I've updated the top post with possible solutions
I guess the root of the problem is that x == 0 is ambiguous: it could be asking whether x is very much like the object 0, or it could be asking whether x is the zero element of its group. For == I think we have no choice but to pick the first interpretation. So I guess I favor option (3): make all functions that explicitly name "zero" or "z" use the group-element interpretation, and leave == alone.
I think == 0 is a better fallback than false (maybe only tried when zero is not applicable?) but otherwise 1 seems like the more desirable behavior to me - if there is no zero element, the answer is no, why error? I anticipate people would immediately start defining zero(::String) in response to the error they would get here, and I don't think we should encourage that
Or perhaps iszero(x) = (x == zero(x))? I'm fine with getting an error from countnz(["str"]).
isn't that what it is now?
+1 to the idea of making countnz call iszero though.
I've only just started reading the issue, but the status quo actual seems best to me.
I think the iszero usage can be easily written:
count(iszero, [1, 2, 3, 0])
Along the lines of what @vtjnash is proposing, I propose getting rid of the countnz function entirely in favor of count(!iszero, A) or whatever your favorite predicate is.
I think you mean count(!iszero, [1, 2, 3, 0]), right?
Removing countnz entirely is ok with me too. I like deleting stuff :)
Efficient implementation for sparse is roughly nnz(S)*pred(default) + count(p, S.values).
Fixed by #23485.
Most helpful comment
Removing
countnzentirely is ok with me too. I like deleting stuff :)