# Subtyping Dict

**URL:** <https://discourse.julialang.org/t/subtyping-dict/56720>\
**Category:** General Usage\
**Created:** [March 8, 2021, 9:47am UTC](https://discourse.julialang.org/t/subtyping-dict/56720 "2021-03-08T09:47:25Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![imLew](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/imlew/32/22324_2.png) [@imLew](https://discourse.julialang.org/u/imLew)\
**Post date:** [March 8, 2021, 9:47am UTC](https://discourse.julialang.org/t/subtyping-dict/56720/1 "2021-03-08T09:47:25Z")

</div>

I’m using `Dict`s to store the parameters store the parameters of a problem to be solved by an algorithm. There are different types of problems and I would like to use multiple dispatch to organize the code for running the algorithm and plotting the results.

Right now I have something like

```julia
function run_problem1(params)
    Do something generic
    Do something specific to problem 1
end
function run_problem2(params)
    Do something generic
    Do something specific to problem 2
end
function plot_problem1(results)
    Do something specific to problem 1
end
function plot_problem2(results)
    Do something specific to problem 1
end

```

The duplication of code isn’t great and I am looking for a way to minimize it.  
Ideally I would like to have something that looks like

```julia
function run(params::problem_type)
    Do specific thing
end
function start_run(params)
    Do generic thing
    run(params)
end
function plot(params::problem_type)
    do specific thing
end

```

However I don’t want to give up all the sweet properties of `Dict`s, so I don’t want to rewrite everything to use structs.  
I realize I could define a struct and then define all the `Dict` methods for that struct but that seems like the kind of reinventing the wheel people always advise against.  
So is there a way I create a Dict with a type? I.e. `Problem1Params<:Dict`, which will allow me to use multiple dispatch while still using Dicts?

---

<div class="post-metadata">

**Author:** ![dfdx](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dfdx/32/120_2.png) [@dfdx](https://discourse.julialang.org/u/dfdx)\
**Post date:** [March 8, 2021, 11:18am UTC](https://discourse.julialang.org/t/subtyping-dict/56720/2 "2021-03-08T11:18:36Z")

</div>

This thread might be relevant to your problem:

> [@Forward all methods of a structure](https://discourse.julialang.org/t/forward-all-methods-of-a-structure/11783/4):
>
> Thanks for your reply, code generation is a good idea, but not good enough. For future extensions, we still have to define two set of functions for both Daggered and original version. Adjoint has the same problem.

In particular, the `@forward` macro is what I would use in this situation.

---

<div class="post-metadata">

**Author:** ![mrkosjan](https://avatars.discourse-cdn.com/v4/letter/m/ce73a5/32.png) [@mrkosjan](https://discourse.julialang.org/u/mrkosjan)\
**Post date:** [March 8, 2021, 11:41am UTC](https://discourse.julialang.org/t/subtyping-dict/56720/3 "2021-03-08T11:41:46Z")

</div>

Which properties of `Dicts` are important to you?

I was dealing with a very similar issue and ended up with following: my run functions take 2 arguments, special solver struct, e.g. `Solver1Params` or `Solver2Params` that contain the parameters for specific algorithms and that are dispatched on. I feel like the prior definition of all parameters in the struct gives me better control and readability.  
For parameters that are independent of the specific algorithm and are more problem specific, I use dictionaries. To build them, I use the `@dict` macro from DrWatson.jl (which by the way is really useful package) that builds dictionary from variables.

Anyway, to do what you are asking, according to the [docs](https://docs.julialang.org/en/v1/base/collections/#Dictionaries), I believe you would have to subclass `AbstractDict` and implement parts of the interface that you require. The doc seems to be [here](https://docs.julialang.org/en/v1/base/collections/#Base.AbstractDict), but I couldn’t find the interface documented in a similar ways as it is for [iteration](https://docs.julialang.org/en/v1/manual/interfaces/#Interfaces). However, looking at the [sources for Dicts,](https://docs.julialang.org/en/v1/base/collections/#Base.AbstractDict) it looks to me like it could be a lot of work with potentially mixed results (you would have to do write the interface for each of the concrete types, bar some packages that simulate subclassing and automate that for you).

Overall, from my understanding, encapsulating the dicts in struct could be less work and easier to maintain than subtyping `AbstractDict`, but I am curious to know what you come up with. I think a lot depends on what Dict properties are important to you.

---

<div class="post-metadata">

**Author:** ![heliosdrm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heliosdrm/32/3851_2.png) [@heliosdrm](https://discourse.julialang.org/u/heliosdrm)\
**Post date:** [March 8, 2021, 1:03pm UTC](https://discourse.julialang.org/t/subtyping-dict/56720/4 "2021-03-08T13:03:22Z")

</div>

Would this be a satisfactory workaround?

```julia
abstract type AbstractProblem end
struct Problem1 <: AbstractProblem end
struct Problem2 <: AbstractProblem end

function run(::Type{Problem1}, params)
    Do specific thing
end
function run(::Type{Problem2}, params)
    Do specific thing
end

function start_run(::Type{P}, params) where {P <: AbstractProblem}
    Do generic thing
    run(P, params)
end

function plot(::Type{Problem1}, params)
    Do specific thing
end
function plot(::Type{Problem2}, params)
    Do specific thing
end

```

So you can run it as

```julia
julia> start_run(Problem1, params)

```

etc.

---

<div class="post-metadata">

**Author:** ![imLew](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/imlew/32/22324_2.png) [@imLew](https://discourse.julialang.org/u/imLew)\
**Post date:** [March 8, 2021, 2:16pm UTC](https://discourse.julialang.org/t/subtyping-dict/56720/5 "2021-03-08T14:16:03Z")

</div>

Thanks for the replies.  
Though I am still interested in how this could be done, I am going to try @heliosdrm’s suggestion as it seems much easier to work with than actually combining a new type with `Dict`.

Edit: It seems to work pretty well so far with

```julia
params = Dict(:problem_type => :Problem1, ...)
function run(::Val{:Problem1}, params) ... end
function start_run(params)
    ...
    run(Val(params[:problem_type]), params)
end

```

---

<div class="post-metadata">

**Author:** ![heliosdrm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heliosdrm/32/3851_2.png) [@heliosdrm](https://discourse.julialang.org/u/heliosdrm)\
**Post date:** [March 8, 2021, 3:26pm UTC](https://discourse.julialang.org/t/subtyping-dict/56720/6 "2021-03-08T15:26:10Z")

</div>

You found yourself a solution, good job!

Just in case, I would point out that if performance is relevant for your problem, with that solution you are adding some type-instabilities that might slow down your code. Nevertheless, if that’s not a pain point in your use case and the solution works, you can just go ahead and focus on more relevant parts of your problem.

---

<div class="post-metadata">

**Author:** ![imLew](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/imlew/32/22324_2.png) [@imLew](https://discourse.julialang.org/u/imLew)\
**Post date:** [March 8, 2021, 4:51pm UTC](https://discourse.julialang.org/t/subtyping-dict/56720/7 "2021-03-08T16:51:33Z")

</div>

Thanks, it’s basically your solution without the separate `struct` definition.

Is the type instability down to using `::Val` instead of a predefined struct?

---

<div class="post-metadata">

**Author:** ![heliosdrm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heliosdrm/32/3851_2.png) [@heliosdrm](https://discourse.julialang.org/u/heliosdrm)\
**Post date:** [March 8, 2021, 6:00pm UTC](https://discourse.julialang.org/t/subtyping-dict/56720/8 "2021-03-08T18:00:56Z")

</div>

There are two possible sources of type instability added by this solution:

One is, as you guess, your using `Val`. I understand that this may be a bit confusing at first sight: `Val(:Problem1)` is of a concrete type, but `Val(params[:problem_type])`, as found in `start_run`, is _not_ concrete, because your function does not know at compile time what will be the content of the thing inside the parentheses (i.e. the parameter of the `Val` type). So, that particular function won’t be properly optimized. If the rest of the code in that function is performance-sensitive, you may want to use a “function barrier”. See the entries about [value types](https://docs.julialang.org/en/v1/manual/performance-tips/#man-performance-value-type) and [function barriers](https://docs.julialang.org/en/v1/manual/performance-tips/#kernel-functions) in the Julia manual.

The other (potential) source is that if the types of keys/values of `params` are other than `Symbol` for the rest of entries, adding `:problem_type => :Problem1` will force you to use a dictionary with abstract types. For instance, maybe the dictionary _without_ `:problem_type` was something like `Dict(:a=>1, :b=>1.5)`, i.e. a `Dict{Symbol, Float64}`. But with the new item it will be a `Dict{Symbol, Any}`. This is also completely legal, but functions that have to get values from that dictionary won’t be able to infer what type of value should be expected. (This being said, if `params` already combined different types of values, adding that new item will make no difference.)

---

<div class="post-metadata">

**Author:** ![heliosdrm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heliosdrm/32/3851_2.png) [@heliosdrm](https://discourse.julialang.org/u/heliosdrm)\
**Post date:** [March 8, 2021, 6:44pm UTC](https://discourse.julialang.org/t/subtyping-dict/56720/9 "2021-03-08T18:44:25Z")

</div>

> [@heliosdrm](#):
>
> f the rest of the code in that function is performance-sensitive, you may want to use a “function barrier”.

To make it clearer: as by your definition

```julia
function start_run(params)
    ...
    run(Val(params[:problem_type]), params)
end

```

If the code abstracted by the “dots” is complex (and type stable) it’s recommended to wrap it into a different function, so that it can be compiled properly, and not spoiled by the type instability of the following line.
