# How to avoid supplying exact types in a Dict constructor?

**URL:** <https://discourse.julialang.org/t/how-to-avoid-supplying-exact-types-in-a-dict-constructor/51510>\
**Category:** New to Julia\
**Created:** [December 9, 2020, 10:54am UTC](https://discourse.julialang.org/t/how-to-avoid-supplying-exact-types-in-a-dict-constructor/51510 "2020-12-09T10:54:44Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![stefkuypers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefkuypers/32/19185_2.png) [@stefkuypers](https://discourse.julialang.org/u/stefkuypers)\
**Post date:** [December 9, 2020, 10:54am UTC](https://discourse.julialang.org/t/how-to-avoid-supplying-exact-types-in-a-dict-constructor/51510/1 "2020-12-09T10:54:44Z")

</div>

Hi,

When I have a type hierarchy where TC is a concrete implementation of type T and I have defined a struct as follows:

```julia
struct Foo
    d::Dict{T,Any}
end

```

What do I need to do to be able to call the constructor as follows:

```julia
Foo(Dict(TC() => value))

```

Instead of having to call it as:

```julia
Foo(Dict{T, Any}(TC() => value))

```

And what is the logic behind it?

Thanks in advance,  
Stef

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [December 9, 2020, 10:57am UTC](https://discourse.julialang.org/t/how-to-avoid-supplying-exact-types-in-a-dict-constructor/51510/2 "2020-12-09T10:57:37Z")

</div>

> [@stefkuypers](#):
>
> What do I need to do to be able to call the constructor as follows:

Nothing?

```julia
julia> abstract type T end

julia> struct TC <: T end

julia> struct Foo
           d::Dict{T,Any}
       end

julia> Foo(Dict(TC() => 1))
Foo(Dict{T,Any}(TC() => 1))

```

Maybe you have a full MWE that illustrates your point?

---

<div class="post-metadata">

**Author:** ![stefkuypers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefkuypers/32/19185_2.png) [@stefkuypers](https://discourse.julialang.org/u/stefkuypers)\
**Post date:** [December 9, 2020, 12:15pm UTC](https://discourse.julialang.org/t/how-to-avoid-supplying-exact-types-in-a-dict-constructor/51510/3 "2020-12-09T12:15:52Z")

</div>

Hi,

@kristoffer.carlsson well, that’s what I thought too. Here’s the source code:

```julia
abstract type Blueprint end

struct ConsumableBlueprint <: Blueprint
    type_id::UUID
    name::String
    ConsumableBlueprint(name::String) = new(uuid4(), name)
end

struct ProducerBlueprint <: Blueprint
    type_id::UUID
    name::String
    lifecycle::Restorable
    restore_res::Dict{Blueprint,Int64}
    restore::Float64
    batch_req::Dict{Blueprint,Int64} # Required input per batch
    batch::Dict{Blueprint,Int64} # batch per batch. The Blueprint and the number of items per blueprint.
    max_production::Int64 # Max number of batches per production cycle

    ProducerBlueprint(
        name::String,
        lifecycle::Restorable = Restorable();
        restore_res::Dict{Blueprint,Int64} = Dict{Blueprint,Int64}(),
        restore::Real = 0,
        batch_req::Dict{Blueprint,Int64} = Dict{Blueprint,Int64}(),
        batch::Dict{Blueprint,Int64} = Dict{Blueprint,Int64}(),
        max_production::Int64 = INF
    ) = new(uuid4(), name, lifecycle, restore_res, restore, batch_req, batch, max_production)
end

```

When I execute the following:

```julia
labour_bp = ConsumableBlueprint("Labour")
food_bp = ConsumableBlueprint("Food")
factory_bp = ProducerBlueprint(
        "Factory",
        batch_req = Dict(labour_bp => 2),
        batch = Dict(food_bp => 1)
    )

```

I get this error:

```julia
ERROR: TypeError: in keyword argument batch_req, expected Dict{Blueprint,Int64}, got a value of type Dict{ConsumableBlueprint,Int64}
Stacktrace:
 [1] top-level scope at none:1

```

Kind regards,  
Stef

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [December 9, 2020, 12:18pm UTC](https://discourse.julialang.org/t/how-to-avoid-supplying-exact-types-in-a-dict-constructor/51510/4 "2020-12-09T12:18:40Z")

</div>

Again, please provide an MWE (emphasis on the W (working)). Copy pasting this I get

```julia
ERROR: UndefVarError: Restorable not defined

```

---

<div class="post-metadata">

**Author:** ![malacroi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/malacroi/32/19745_2.png) [@malacroi](https://discourse.julialang.org/u/malacroi)\
**Post date:** [December 9, 2020, 1:26pm UTC](https://discourse.julialang.org/t/how-to-avoid-supplying-exact-types-in-a-dict-constructor/51510/5 "2020-12-09T13:26:13Z")

</div>

In your example, when you try to build `factory_bp` you set a field with `batch_req = Dict(labour_bp => 2)`, but `labour_bp` at that time is concretely typed as `ConsumableBlueprint`, so the resulting `Dict` is not a `Dict{Blueprint,Int64}` it’s a `Dict{ConsumableBlueprint,Int64}`. You have at least a few choices depending on how it’s going to be used.

1. If `ProduceBlueprint` is only going to read from the `Dict`, then its fields could be changed to `Dict{<:Blueprint,Int64}` so that this kind of input is allowed. This would require changing the fields of the `struct` and of its constructor.
2. If `ProduceBlueprint` needs to be able to write arbitrary blueprints to the `Dict` objects it receives, then you need `batch_req = Dict{Blueprint,Int64}(labour_bp => 2)`

---

<div class="post-metadata">

**Author:** ![FPGro](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fpgro/32/20822_2.png) [@FPGro](https://discourse.julialang.org/u/FPGro)\
**Post date:** [December 9, 2020, 1:39pm UTC](https://discourse.julialang.org/t/how-to-avoid-supplying-exact-types-in-a-dict-constructor/51510/6 "2020-12-09T13:39:34Z")

</div>

Just for the sake of providing options:

- 
  1. Add an outer constructor for which restore\_res, restore, and batch are untyped and `convert(Dict{Blueprint, Int64}, batch)` them before passing to the inner constructor

---

<div class="post-metadata">

**Author:** ![stefkuypers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefkuypers/32/19185_2.png) [@stefkuypers](https://discourse.julialang.org/u/stefkuypers)\
**Post date:** [December 9, 2020, 1:41pm UTC](https://discourse.julialang.org/t/how-to-avoid-supplying-exact-types-in-a-dict-constructor/51510/7 "2020-12-09T13:41:10Z")

</div>

@kristoffer.carlsson the full code is available on GitHub. The code in the following file:

[https://github.com/lpu-howest/loreco-abm/blob/main/cockpit/start\_cockpit.jl](https://github.com/lpu-howest/loreco-abm/blob/main/cockpit/start_cockpit.jl)

initialises all structs.

The unit test I’m trying to run is the “Producer” test set near the bottom of the following file:  
[https://github.com/lpu-howest/loreco-abm/blob/main/cockpit/production/unit\_test.jl](https://github.com/lpu-howest/loreco-abm/blob/main/cockpit/production/unit_test.jl)

Kind regards,  
Stef

---

<div class="post-metadata">

**Author:** ![stefkuypers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefkuypers/32/19185_2.png) [@stefkuypers](https://discourse.julialang.org/u/stefkuypers)\
**Post date:** [December 14, 2020, 3:53pm UTC](https://discourse.julialang.org/t/how-to-avoid-supplying-exact-types-in-a-dict-constructor/51510/8 "2020-12-14T15:53:02Z")

</div>

@malacroi, I went for the first solution since ProducerBlueprint doesn’t need to write anything to the Dict.

So I thought I could do something similar for Entities:

```julia
struct Entities
    entities::Dict{Blueprint,Vector{Entity}}
    Entities() = new(Dict{Blueprint,Vector{Entity}}())
end

function Entities(resources::Dict{<:Blueprint,Vector{<:Entity}})
    entities = Entities()

    for blueprint in keys(resources)
        for entity in resources[blueprint]
            push!(entities, entity)
        end
    end

    return entities
end

Base.keys(entities::Entities) = keys(entities.entities)
Base.values(entities::Entities) = values(entities.entities)
Base.getindex(entities::Entities, index::Blueprint) = entities.entities[index]
Base.setindex!(entities::Entities, e::Array{Entity,1}, index::Blueprint) = (entities.entities[index] = e)

function Base.push!(entities::Entities, entity::Entity)
    if entity.blueprint in keys(entities)
        push!(entities[entity.blueprint], entity)
    else
        entities[entity.blueprint] = Vector{Entity}([entity])
    end

    return entities
end

function Base.pop!(entities::Entities, blueprint::Blueprint)
    if blueprint in keys(entities)
        e = pop!(entities[blueprint])

        if length(entities[blueprint]) == 0
            pop!(entities.entities, blueprint)
        end

        return e
    else
        return nothing
    end
end

```

But when I call the second constructor with:

```julia
labour_bp = ConsumableBlueprint("Labour")
Entities(Dict(labour_bp => [Consumable(labour_bp), Consumable(labour_bp)]))

```

where Consumable \<: Entity, I get the following error:

```julia
ERROR: MethodError: no method matching Entities(::Dict{ConsumableBlueprint,Array{Consumable,1}})
Closest candidates are:
  Entities() at /Users/stef/Programming/Julia Projects/loreco-abm/cockpit/production/entities.jl:76
  Entities(::Dict{var"#s50",Array{var"#s49",1} where var"#s49"<:Entity} where var"#s50"<:Blueprint) at /Users/stef/Programming/Julia Projects/loreco-abm/cockpit/production/entities.jl:79
Stacktrace:
 [1] top-level scope at none:1

```

var"#s50" is labour\_bp which is \<: Blueprint and var"#s49" are the 2 Consumables which are both \<: Entity

How come the same trick doesn’t work here?

Thanks in advance,  
Stef

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [December 15, 2020, 8:15am UTC](https://discourse.julialang.org/t/how-to-avoid-supplying-exact-types-in-a-dict-constructor/51510/9 "2020-12-15T08:15:11Z")

</div>

> [@stefkuypers](#):
>
> How come the same trick doesn’t work here?

Since you specified an [inner constructor](https://docs.julialang.org/en/v1/manual/constructors/#man-inner-constructor-methods) `Entities()` with no arguments, it cannot take a `Dict`.

Perhaps you meant an outer constructor?

---

<div class="post-metadata">

**Author:** ![stefkuypers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefkuypers/32/19185_2.png) [@stefkuypers](https://discourse.julialang.org/u/stefkuypers)\
**Post date:** [December 15, 2020, 10:25am UTC](https://discourse.julialang.org/t/how-to-avoid-supplying-exact-types-in-a-dict-constructor/51510/10 "2020-12-15T10:25:43Z")

</div>

@Tamas_Papp That’s the thing, I did define an outer constructor which takes a Dict:

```julia
function Entities(resources::Dict{<:Blueprint,Vector{<:Entity}})
    entities = Entities()

    for blueprint in keys(resources)
        for entity in resources[blueprint]
            push!(entities, entity)
        end
    end

    return entities
end

```

Unless I’m mistaken somehow.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [December 15, 2020, 12:02pm UTC](https://discourse.julialang.org/t/how-to-avoid-supplying-exact-types-in-a-dict-constructor/51510/11 "2020-12-15T12:02:38Z")

</div>

Your MWE does not run as `Entity` is not defined. It is hard to help without a self-contained MWE, see

> [@Please read: make it easier to help you](https://discourse.julialang.org/t/psa-make-it-easier-to-help-you/14757/):
>
> Welcome to the Julia Discourse! We are enthusiastic about helping Julia programmers, both beginner and experienced. This public service announcement (PSA) outlines best practices when asking for help. Following these points makes it easier for us to help you and more likely you’ll get a prompt, useful answer. Keywords are highlighted to make it easier to refer to specific points. Choose a descriptive title that captures the key part of your question, eg “plots with multiple axes” instead of …

---

<div class="post-metadata">

**Author:** ![stefkuypers](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefkuypers/32/19185_2.png) [@stefkuypers](https://discourse.julialang.org/u/stefkuypers)\
**Post date:** [December 16, 2020, 9:35am UTC](https://discourse.julialang.org/t/how-to-avoid-supplying-exact-types-in-a-dict-constructor/51510/12 "2020-12-16T09:35:16Z")

</div>

My apologies for providing an incomplete MWE.

Here is an executable one.

```julia
abstract type Blueprint end

struct ABlueprint <: Blueprint
    val::Int64
    ABlueprint(val::Int64=0) = new(val)
end

abstract type Entity end

struct AnEntity <: Entity
    val::Int64
    AnEntity(val::Int64=0) = new(val)
end

struct Entities
    entities::Dict{Blueprint,Vector{Entity}}
    Entities() = new(Dict{Blueprint,Vector{Entity}}())
end

function Entities(resources::Dict{<:Blueprint,Vector{<:Entity}})
    entities = Entities()

    for blueprint in keys(resources)
        for entity in resources[blueprint]
            push!(entities, entity)
        end
    end

    return entities
end

Entities(Dict(ABlueprint() => [AnEntity()]))

```

The last line results in the following error:

```julia
ERROR: MethodError: no method matching Entities(::Dict{ABlueprint,Array{AnEntity,1}})
Closest candidates are:
  Entities() at none:3
  Entities(::Dict{var"#s10",Array{var"#s9",1} where var"#s9"<:Entity} where var"#s10"<:Blueprint) at none:1
Stacktrace:
 [1] top-level scope at none:1

```

When calling the methods() function I get the following output:

```julia
 methods(Entities)
# 2 methods for type constructor:
[1] Entities() in Main at none:3
[2] Entities(resources::Dict{var"#s10",Array{var"#s9",1} where var"#s9"<:Entity} where var"#s10"<:Blueprint) in Main at none:1

```

My assumption was that I could therefore call the outer constructor of Entities() with a Dict that contains implementations of Blueprint and Entity.

Thanks in advance,  
Stef

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [December 16, 2020, 10:11am UTC](https://discourse.julialang.org/t/how-to-avoid-supplying-exact-types-in-a-dict-constructor/51510/13 "2020-12-16T10:11:00Z")

</div>

If you insist on this type signature, use

```julia
function Entities(resources::Dict{S,Vector{T}}) where {S <: Blueprint, T <: Entity}
    ...

```

See [invariance](https://docs.julialang.org/en/v1/manual/types/#Parametric-Composite-Types).

That said, since you are traversing the input anyway, I think it is better to just allow all kinds of arguments that support `pairs` and use that interface.
