Julia: hashing of array of arrays with length > 3

Created on 29 Jun 2018  路  8Comments  路  Source: JuliaLang/julia

julia> hash([["asd"], ["asd"], ["asad"]])
ERROR: MethodError: no method matching -(::String, ::String)
Stacktrace:
 [1] _broadcast_getindex_evalf at .\broadcast.jl:585 [inlined]
 [2] _broadcast_getindex at .\broadcast.jl:558 [inlined]
 [3] getindex at .\broadcast.jl:518 [inlined]
 [4] copy at .\broadcast.jl:769 [inlined]
 [5] materialize at .\broadcast.jl:735 [inlined]
 [6] broadcast(::typeof(-), ::Array{String,1}, ::Array{String,1}) at .\broadcast.jl:713
 [7] - at .\arraymath.jl:39 [inlined]
 [8] hash(::Array{Array{String,1},1}, ::UInt64) at .\abstractarray.jl:2104
 [9] hash(::Array{Array{String,1},1}) at .\hashing.jl:18
 [10] top-level scope at none:0

Another version fails at the broadcast check, but I think that's just the same problem with a different shape.
Problem seems to be the isapplicable(-, x1, x2) branch in https://github.com/JuliaLang/julia/blob/master/base/abstractarray.jl#L2107.
Since there is -(x::AbstractArray, y::AbstractArray) in https://github.com/JuliaLang/julia/blob/master/base/arraymath.jl#L36, that becomes true, even though the elements (strings) of the array don't support -.

bug hashing

Most helpful comment

It's not that applicable is hard to use correctly, it's that it only means "has a method", not "has a method and won't throw an error". For something as generic as hashing, we need to avoid functions that might throw errors unless the error would mean computing a hash is not possible.

All 8 comments

Sigh. applicable is really impossible to use correctly in Julia. The best way to fix this is https://github.com/JuliaLang/julia/pull/26022.

Wouldn't isapplicable(-, x::AbstractArray, y::AbstractArray)=isapplicable(-, eltype(x), eltype(y) fix this problem?

Is isapplicable even type stable?

julia> test() = isapplicable(-,Int,Int)
test (generic function with 3 methods)

julia> @code_warntype test()
Variables:
  #self# <optimized out>

Body:
  begin
      return (Main.isapplicable)(Main.-, Main.Int, Main.Int)::Any
  end::Any

Doesn't look like it, so this is also a major performance issue in what seems to be performance sensitive code...

Nevermind, should have tested this:

 test() = applicable(-,Int,Int)
julia> @code_warntype test()
Variables:
  #self# <optimized out>

Body:
  begin
      return (Main.applicable)(Main.-, Main.Int, Main.Int)::Bool
  end::Bool

But it's still pretty slow:
`Julia julia> @btime test() 36.102 渭s (24 allocations: 1.13 KiB) false

It's not that applicable is hard to use correctly, it's that it only means "has a method", not "has a method and won't throw an error". For something as generic as hashing, we need to avoid functions that might throw errors unless the error would mean computing a hash is not possible.

FWIW, https://github.com/JuliaLang/julia/pull/25822 restricts that algorithm to arrays of Numbers, which would also fix that error. Though we would still assume that if - is defined for Number types, is has to work (or throw OverflowError, which is handled). Overall I still think simplifying this radically would be better (#26022).

fixed by #26022

Was this page helpful?
0 / 5 - 0 ratings