IMHO, there are two things missing:
1) You should define outer constructor for `DefaultDict(val, Dict())`;
2) You should make your promotion rules parametric.
On Sunday, August 23, 2015 at 7:48:11 PM UTC+2, Joshua Ballanco wrote:
>
> Hello all,
>
> Apologies in advance if I’m missing something obvious. I’ve only just
> started experimenting with some of the more advanced features of Julia’s
> types, and I’ve hit a bit of a wall…
>
> Say I wanted to replicate something like Python’s
> `collections.defaultdict` or Ruby’s `Hash` class with a default value. So
> far this is what I have:
>
> ——8<——8<——
>
> immutable DefaultDict{K, V} <: Associative{K, V}
> default::V
> dict::Dict{K, V}
> end
>
> function DefaultDict(val)
> return DefaultDict(val, Dict())
> end
>
> function Base.getindex{K, V}(dd::DefaultDict{K, V}, key::K)
> if haskey(dd.dict, key)
> getindex(dd.dict, key)
> else
> dd.default
> end
> end
>
> ——8<——8<——
>
> Ideally, I’d like to avoid having to re-implement all of the methods one
> would expect `Dict` to work with, since I can trivially convert from a
> `DefaultDict`:
>
> ——8<——8<——
>
> Base.convert(::Type{Associative}, dd::DefaultDict) = dd.dict
> Base.promote_rule(::Type{Associative}, ::Type{DefaultDict}) =
> Associative
>
> ——8<——8<——
>
> However, this doesn’t seem to work as I had hoped it might:
>
> ——8<——8<——
>
> > foo = DefaultDict(42)
> > foo['a'] = 1
> ERROR: MethodError: `setindex!` has no method matching
> setindex!(::DefaultDict{Any,Any}, ::Int64, ::Char)
> Closest candidates are:
> setindex!(::Associative{K,V}, ::Any, ::Any, ::Any, ::Any…)
>
> ——8<——8<——
>
> Sure, implementing `setindex!`, `length`, `start`, etc. would be trivial,
> but I’m more worried about third-party code that expects `Dict` arguments.
> In principle I’d like to still be able to pass instances of `DefaultDict`
> to methods that would otherwise expect `Dict`s.
>
> Am I completely off-base with this approach? What’s the most “Julian”
> solution to specializing types in this manner?
>
> Cheers,
>
> Josh
>