Currently the experimental api for error hint registration allows same handler to be registered multiple times. And the handler is called multiple times when triggered.
Bear with me on this not so minimal example:
using Markdown
using StyledStrings
struct MemberAccessException <: Exception
objType::DataType
x::Symbol
end
Base.getproperty(d::Dict, x::Symbol) = begin
if x in propertynames(d)
return getfield(d, x)
else
throw(MemberAccessException(typeof(d), x))
end
end
function Base.showerror(io::IO, exc::MemberAccessException)
@nospecialize
println(io, "MemberAccessError: member access of this field on this DataType is not entertained.\n")
Base.Experimental.show_error_hints(io, exc)
end
function memberAccessHandler(io, exc)
@nospecialize
x = exc.x
objType = exc.objType
if objType <: Dict
println(io,
"""
The field `$x` is not a member of Dict type. In case you
are trying to access values using keys consider
using `indexing` operation.
""")
println(io, styled"{bold: Example:}")
println(io, styled"{bold: ≡≡≡≡≡≡≡}")
print(io, styled"{bold, green: julia> }")
println(io, "dict = Dict(:$(x)=>1)")
print(io, styled"{bold, green: julia> }")
println(io, "dict[:$(x)]")
else
println(io,
"""
This datatype does not allow member access of this field -`$(x)` for end users.
Please refer to documentation on $(objType) on access rights and means to do it.
"""
)
end
end
Base.Experimental.register_error_hint(memberAccessHandler, MemberAccessException)
Base.Experimental.register_error_hint(memberAccessHandler, MemberAccessException)
Base.Experimental.register_error_hint(memberAccessHandler, MemberAccessException)
h = Dict(:a=>5)
h.c
julia> Base.Experimental._hint_handlers
IdDict{Type, Vector{Any}} with 4 entries:
MemberAccessException => [memberAccessHandler, memberAccessHandler, memberAccessHandler]
MethodError => [noncallable_number_hint_handler, nonsetable_type_hint_handler, string_concatenati…
UndefVarError => [UndefVarError_hint]
FieldError => [fielderror_hint_handler]
_hint_handlers
stored multiple memberAccessHandler
handlers.
From my perspective this should not allowed. I see two options:
- Check if this handler exists already and push! only if its not already registered.
- replace existing handler with new handler.