I get a method error if I try to create a Dict with Dates.Hour(1)
and Dates.Month(1)
as keys. All other combinations of keys work, but these two exact values cannot exist as keys together in the same Dict.
I understand why Dates.Hour(1) == Dates.Month(1)
would throw a MethodError
, but I do not understand why this should happen when adding them as keys to a Dict
, and why the same error does not show up if, for example, we were to use Dates.Hour(2)
or Dates.Year(1)
instead.
More details at https://discourse.julialang.org/t/cannot-use-a-dates-hour-and-dates-month-as-keys-in-the-same-dict/
julia> versioninfo()
Julia Version 0.6.3-pre.2
Commit c011bb7 (2018-05-08 17:03 UTC)
DEBUG build
Platform Info:
OS: Linux (x86_64-linux-gnu)
CPU: Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz
WORD_SIZE: 64
BLAS: libopenblas (USE64BITINT DYNAMIC_ARCH NO_AFFINITY Haswell)
LAPACK: libopenblas64_
LIBM: libopenlibm
LLVM: libLLVM-3.9.1 (ORCJIT, haswell)
julia> DATEPART_DISPLAY = Dict{Dates.Period, AbstractString}()
Dict{Base.Dates.Period,AbstractString} with 0 entries
julia> DATEPART_DISPLAY[Dates.Month(1)] = "%b %Y"
"%b %Y"
julia> DATEPART_DISPLAY[Dates.Hour(1)] = "%b %d %Y, %H:%M"
ERROR: MethodError: no method matching ==(::Base.Dates.Hour, ::Base.Dates.Month)
Closest candidates are:
==(::Union{Base.Dates.Day, Base.Dates.Hour, Base.Dates.Microsecond, Base.Dates.Millisecond, Base.Dates.Minute, Base.Dates.Nanosecond, Base.Dates.Second, Base.Dates.Week}, ::Union{Base.Dates.Month, Base.Dates.Year}) at dates/periods.jl:443
==(::Base.Dates.Period, ::Base.Dates.Period) at dates/periods.jl:63
==(::Any, ::Any) at operators.jl:52
...
Stacktrace:
[1] ==(::Base.Dates.Hour, ::Base.Dates.Month) at ./dates/periods.jl:443
[2] ht_keyindex2(::Dict{Base.Dates.Period,AbstractString}, ::Base.Dates.Hour) at ./dict.jl:366
[3] setindex!(::Dict{Base.Dates.Period,AbstractString}, ::String, ::Base.Dates.Hour) at ./dict.jl:421
As noted on Discourse, this actually works on 0.7. Not sure what changed.
There is still an error for Hour(1) == Month(1)
, due to a definition that explicitly throws a MethodError:
(==)(x::FixedPeriod, y::OtherPeriod) = throw(MethodError(==, (x, y)))
(==)(x::OtherPeriod, y::FixedPeriod) = throw(MethodError(==, (x, y)))
The usual style in julia (as assumed e.g. by Dict
) is just to return false
; I think these methods should be changed.
FWIW, we could also define isequal
methods that return false
, and keep throwing an error for ==
, since dicts only need the former.
We don't generally have ==
methods that throw an error because of the types of their arguments being incompatible. That is a design that we've considered in the past and that I've even advocated for from time to time, but as we have not adopted that approach, this case is just inconsistent.
FWIW, I've currently worked around it in my code by defining the aforementioned isequal
methods in my own code just before my Dict
with a comment to remove it once this bug is fixed.
Thanks for the suggestion, and I hope it does get fixed at some point.
Patched it in one of my branches, the original discussion that lead to the introduction of the “offending” lines were in #21378 by @omus. Happy to receive comments or order to submit a PR, especially from someone with opinions on the hellishly complicated topic of time – personally I am just going through issues, finding this to be a silly gotcha, and coding late on a Friday night for kicks.
Yes a PR with that would be fine. Even better if it can be fixed by just deleting those methods.
Tried deleting, but it tries to promote and goes down in flames. Filing PR to move implementation specific discussion there.
Fixed by #27165.
Is this going to be backported to 0.6?
It seems like a behavioral change rather than a bug fix, no?
Most helpful comment
There is still an error for
Hour(1) == Month(1)
, due to a definition that explicitly throws a MethodError:The usual style in julia (as assumed e.g. by
Dict
) is just to returnfalse
; I think these methods should be changed.