# Dictionaries with abstract types for keys/values as function arguments

**URL:** https://discourse.julialang.org/t/dictionaries-with-abstract-types-for-keys-values-as-function-arguments/47063
**Category:** General Usage
**Tags:** question
**Created:** [September 22, 2020, 12:24pm UTC](https://discourse.julialang.org/t/dictionaries-with-abstract-types-for-keys-values-as-function-arguments/47063 "2020-09-22T12:24:07Z")
**Posts on this page:** 8
**Page:** 1

<div class="post-metadata">

### Author: ![MJHutchinson](https://avatars.discourse-cdn.com/v4/letter/m/858c86/32.png) [@MJHutchinson](https://discourse.julialang.org/u/MJHutchinson)
#### Post date: [September 22, 2020, 12:24pm UTC](https://discourse.julialang.org/t/dictionaries-with-abstract-types-for-keys-values-as-function-arguments/47063/1 "2020-09-22T12:24:07Z")

</div>

I am currently writing a library that for a number of applications needs to take a dictionary of matrices as arguments. In order to make the functions reasonably general, I wanted to make the key/value types in the function arguments abstract. e.g. something like:

```julia
function print_dict(dict::AbstractDict{<:Real, AbstractArray{<:Real, 2}})
    print(dict)
end

```

(This is not a real function I want to write, just for demonstration of the argument type)

Calling this function with a `dict` of what I assumed to be a valid subtype of the function argument

```julia
dict = Dict{Int, Array{Float32, 2}}()

dict[1] = [10.3 3.4 ; 2.3 4]

print_dict(dict)

```

however gives the following error:

```julia
ERROR: LoadError: MethodError: no method matching print_dict(::Dict{Int64,Array{Float32,2}})
Closest candidates are:
  print_dict(::AbstractDict{var"#s1",AbstractArray{var"#s2",2} where var"#s2"<:Real} where var"#s1"<:Real) at ***/dict_weirdness.jl:1
Stacktrace:
 [1] top-level scope at ***/dict_weirdness.jl:10
 [2] include(::String) at ./client.jl:457
 [3] top-level scope at REPL[1]:1
in expression starting at ***/dict_weirdness.jl:10

```

I expected this to work as you can do things like `AbstractArray{<:Real, 2}` as functional argument types no problem.

Can anyone explain why this does not work, and perhaps suggest any workarounds / better practises?

Thanks in advance, Michael

---

<div class="post-metadata">

### Author: ![hendri54](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hendri54/32/9621_2.png) [@hendri54](https://discourse.julialang.org/u/hendri54)
#### Post date: [September 22, 2020, 12:51pm UTC](https://discourse.julialang.org/t/dictionaries-with-abstract-types-for-keys-values-as-function-arguments/47063/2 "2020-09-22T12:51:46Z")

</div>

It’s not a complete answer, but:

```julia
julia> d=Dict([1 => [1.0 2.0;]])
Dict{Int64,Array{Float64,2}} with 1 entry:
  1 => [1.0 2.0]

julia> print_dict4(d :: AbstractDict{T1, Matrix{T2}}) where {T1 <: Real, T2 <: Real} = println(d);

julia> print_dict4(d)
Dict(1 => [1.0 2.0])

```

whereas

```julia
julia> print_dict5(d :: AbstractDict{T1, AbstractMatrix{T2}}) where {T1 <: Real, T2 <: Real} = println(d);

julia> print_dict5(d)
ERROR: MethodError: no method matching print_dict5(::Dict{Int64,Array{Float64,2}})

```

---

<div class="post-metadata">

### Author: ![mauro3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mauro3/32/292_2.png) [@mauro3](https://discourse.julialang.org/u/mauro3)
#### Post date: [September 22, 2020, 12:52pm UTC](https://discourse.julialang.org/t/dictionaries-with-abstract-types-for-keys-values-as-function-arguments/47063/3 "2020-09-22T12:52:10Z")

</div>

```julia
julia> function print_dict(dict::AbstractDict{<:Real, <:AbstractArray{<:Real, 2}})

           print(dict)

       end

```

works. (now I have to catch a bus, maybe someone else can explain more)

---

<div class="post-metadata">

### Author: ![hendri54](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hendri54/32/9621_2.png) [@hendri54](https://discourse.julialang.org/u/hendri54)
#### Post date: [September 22, 2020, 1:03pm UTC](https://discourse.julialang.org/t/dictionaries-with-abstract-types-for-keys-values-as-function-arguments/47063/4 "2020-09-22T13:03:42Z")

</div>

That’s the point I was missing:

```julia
julia> d=Dict([1 => [1.0 2.0;]])
Dict{Int64,Array{Float64,2}} with 1 entry:
  1 => [1.0 2.0]

julia> isa(d, Dict{<:Real,<:Matrix})
true

julia> isa(d, Dict{<:Real,Matrix})
false

```

and so the dispatch fails without the additional `<:`

---

<div class="post-metadata">

### Author: ![MJHutchinson](https://avatars.discourse-cdn.com/v4/letter/m/858c86/32.png) [@MJHutchinson](https://discourse.julialang.org/u/MJHutchinson)
#### Post date: [September 22, 2020, 10:26pm UTC](https://discourse.julialang.org/t/dictionaries-with-abstract-types-for-keys-values-as-function-arguments/47063/5 "2020-09-22T22:26:50Z")

</div>

Thank you both, this is enlightening. For some reason, I had not expected the need of `<:` before the `AbstractArray`. Typically you don’t need this when the function argument is of `AbstractArray` type, e.g.

```julia
print_array(array::AbstractArray{<:Real, 2}) = println(array)

```

will work fine without the additional `<:`

---

<div class="post-metadata">

### Author: ![hendri54](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hendri54/32/9621_2.png) [@hendri54](https://discourse.julialang.org/u/hendri54)
#### Post date: [September 23, 2020, 12:16am UTC](https://discourse.julialang.org/t/dictionaries-with-abstract-types-for-keys-values-as-function-arguments/47063/6 "2020-09-23T00:16:33Z")

</div>

But you do have the additional `<:` in your last example – it’s the one in front of the `Real`. This is really the point made in the [docs](https://docs.julialang.org/en/v1/manual/types/#Parametric-Types) in a warning box:

> This last point is _very_ important: even though `Float64 <: Real` we **DO NOT** have `Point{Float64} <: Point{Real}` .

---

<div class="post-metadata">

### Author: ![MJHutchinson](https://avatars.discourse-cdn.com/v4/letter/m/858c86/32.png) [@MJHutchinson](https://discourse.julialang.org/u/MJHutchinson)
#### Post date: [September 23, 2020, 2:11pm UTC](https://discourse.julialang.org/t/dictionaries-with-abstract-types-for-keys-values-as-function-arguments/47063/7 "2020-09-23T14:11:14Z")

</div>

Ah okay yes I see.

Is the reason you don’t need the `<:` on the first level of argument type a syntactic nicety then?

i.e. I mean that

```julia
print_array(array::AbstractArray{<:Real, 2}) = println(array)

```

does not need to be

```julia
print_array(array::<:AbstractArray{<:Real, 2}) = println(array)

```

---

<div class="post-metadata">

### Author: ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)
#### Post date: [September 23, 2020, 2:43pm UTC](https://discourse.julialang.org/t/dictionaries-with-abstract-types-for-keys-values-as-function-arguments/47063/8 "2020-09-23T14:43:53Z")

</div>

This is just the same fact that Julia types are _invariant_ ([Types · The Julia Language](https://docs.julialang.org/en/v1/manual/types/#Parametric-Composite-Types)) all over again.

If you have a parametric type `Foo{T}` and types `A <: B`, then it is **not** true that `Foo{A} <: Foo{B}`. It is, however, true that:

```julia
Foo{A} <: (Foo{X} where X <: B)

```

and, equivalently, that:

```julia
Foo{A} <: Foo{<:B}

```

In both cases you are saying “Foo{A} is a subtype of the collection of all types `Foo{X}` where `X` is some subtype of `B`”.

In your case, `Array{Float64, 2} <: AbstractArray{<:Real, 2}`, but that does **not** mean that `Dict{Int, Array{Float64, 2}} <: Dict{Int, AbstractArray{<:Real, 2}}`.

Instead, you can say:

```julia
Dict{Int, Array{Float64, 2}} <: (Dict{Int, A} where A <: AbstractArray{<:Real, 2})

```

or equivalently:

```julia
Dict{Int, Array{Float64, 2}} <: Dict{Int, <:AbstractArray{<:Real, 2}}

```

which means, roughly, "Dict{Int, Array{Float64, 2}} is a member of the set of all types `Dict{Int, A}` in which `A` is some kind of `AbstractArray{R, 2}` and `R` is some kind of `Real`.
