Unitful.jl icon indicating copy to clipboard operation
Unitful.jl copied to clipboard

Equality between `Gain`s is not transitive, prevents correct hashing

Open sostock opened this issue 4 years ago • 2 comments

When comparing a power gain Gain{L, :p} and a root-power gain Gain{L, :rp} with the same L, they get promoted to Gain{L, :?} without changing their numerical values. This breaks the transitivity of ==:

julia> a = Gain{Unitful.Decibel, :rp}(20) # 20 dB (root-power) == factor 10
20 dB

julia> b = Gain{Unitful.Decibel, :p}(20) # 20 dB (power) == factor 100
20 dB

julia> c = Gain{Unitful.Bel, :p}(2) # 2 B (power) == factor 100
2 B

julia> a == b == c
true

julia> a == c
false

Comparison involving numbers is intransitive as well:

julia> a = Gain{Unitful.Decibel, :rp}(20) # 20 dB (root-power) == factor 10
20 dB

julia> b = Gain{Unitful.Decibel, :p}(10) # 10 dB (power) == factor 10
10 dB

julia> c = Gain{Unitful.Decibel, :p}(20) # 20 dB (power) == factor 100
20 dB

julia> a == 10 == b
true

julia> a == b
false

julia> 10 == a == c
true

julia> 10 == c
false

To obtain a consistent behavior for ==, the promotion rules for Gain would have to be changed. It might be difficult to figure out a set of rules that is both practical and consistent, unless one gets rid of Gain{L, :?} altogether.

sostock avatar Nov 26 '20 11:11 sostock

One consequence of the intransitive isequal is that a correct hash implementation for Gain is impossible: We have

  • isequal(Gain{Decibel, :p}(20), Gain{Decibel,:rp}(20)),
  • isequal(Gain{Decibel, :p}(20), 100), and
  • isequal(Gain{Decibel,:rp}(20), 10),

but hash(10) != hash(100).

sostock avatar Nov 30 '20 12:11 sostock