# Dict subtype definition

**URL:** <https://discourse.julialang.org/t/dict-subtype-definition/75496>\
**Category:** General Usage\
**Tags:** type, dictionary\
**Created:** [January 31, 2022, 11:30am UTC](https://discourse.julialang.org/t/dict-subtype-definition/75496 "2022-01-31T11:30:23Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![iskyd](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/iskyd/32/44797_2.png) [@iskyd](https://discourse.julialang.org/u/iskyd)\
**Post date:** [January 31, 2022, 11:30am UTC](https://discourse.julialang.org/t/dict-subtype-definition/75496/1 "2022-01-31T11:30:23Z")

</div>

I want to define the data type of a dictionary using subtype definition.

I’m trying to do seomthing like  
`Dict{String, <:Union{String, Vector{String}}}`

but if I try  
`Dict{String, <:Union{String, Vector{String}}}()`

I got

> MethodError: no method matching (Dict{String, \<:Union{String, Vector{String}}})()

The same thing happen if I try  
`Dict{String,<:Any}()`

The problem is that if I run

`Dict{String,String} <: Dict{String,<:Any}`  
it returns true

but if I run  
`Dict{String,String} <: Dict{String,Any}`  
it return false

And the same things happens for Dict{String,Union{String, Vector{String}}}

How can I use subtype definition in a dictionary?

---

<div class="post-metadata">

**Author:** ![pfitzseb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pfitzseb/32/45566_2.png) [@pfitzseb](https://discourse.julialang.org/u/pfitzseb)\
**Post date:** [January 31, 2022, 12:11pm UTC](https://discourse.julialang.org/t/dict-subtype-definition/75496/2 "2022-01-31T12:11:24Z")

</div>

You just want

```julia
Dict{String, Union{String, Vector{String}}}()

```

to create a container that can take `String`s and `Vector{String}`s as its values.

The important difference between `Foo{Union{Bar, Baz}}` and `Foo{<:Union{Bar,Baz}}` is that the latter is the **union** over **all** `Foo{T}` where `T` is a subtype of `Union{Bar, Baz}` (so `Foo{T} where T <: Union{Bar, Baz}`. That construct is called a `UnionAll` and is very useful to write parametric code, but cannot be instantiated.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [January 31, 2022, 2:53pm UTC](https://discourse.julialang.org/t/dict-subtype-definition/75496/3 "2022-01-31T14:53:04Z")

</div>

> [@iskyd](#):
>
> `Dict{String,String} <: Dict{String,<:Any}`  
> it returns true
> 
> but if I run  
> `Dict{String,String} <: Dict{String,Any}`  
> it return false

In the first half, `Dict{String,<:Any}` is equivalent syntax to `Dict{String,T} where T<:Any`; that is an iterated union a.k.a. `UnionAll`. Iterated unions are abstract types, so they can’t be instantiated; you can check with `isconcretetype`:

```julia
julia> isconcretetype(Dict{String,<:Any})
false

julia> isconcretetype(Dict{String,Any})
true

```

Now for the second half, this is a common mistake, so it’s documented halfway into [this section](https://docs.julialang.org/en/v1/manual/types/#Parametric-Types). Note how `Dict{String,Any}` is a concrete type, and a concrete type cannot be a supertype of another concrete type. The reason it’s a common mistake is that people see the `Any` and think “isn’t that abstract?” Correct, a concrete parametric type can have abstract types as parameters! It’s commonly a way for Julia to make containers that contain multiple concrete types: `Vector{Int}` can only hold `Int` instances, while `Vector{Integer}` holds references to instances of any subtypes of `Integer`.

Extras:

1. It’s worth mentioning that a very important container is an exception to the “concrete parametric type with abstract type parameters” rule: [`Tuple`](https://docs.julialang.org/en/v1/manual/types/#Tuple-Types) (and `NTuple` and `Vararg` by extension, but not `NamedTuple`). So `Tuple{Integer}` is actually abstract and is a supertype of `Tuple{Int}`. It represents the same set of types as an iterated union `Tuple{T} where T<:Integer`, but note that it isn’t one. The reason for this special treatment is that `Tuple` is a `Core` type intended to package concrete types together in one spot, so there wasn’t much point in allowing abstract type parameters that require references to distant spots. There’s been [discussions](https://github.com/JuliaLang/julia/issues/24614) of possibly removing this special treatment in v2.

2. there’s a very niche case where a concrete type can be a supertype of an abstract type: `Type{Int} <: DataType`. It doesn’t have to be `Int`, it can be any type that is an instance of `DataType`.

---

<div class="post-metadata">

**Author:** ![iskyd](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/iskyd/32/44797_2.png) [@iskyd](https://discourse.julialang.org/u/iskyd)\
**Post date:** [January 31, 2022, 6:10pm UTC](https://discourse.julialang.org/t/dict-subtype-definition/75496/4 "2022-01-31T18:10:22Z")

</div>

Thanks for the answer. I just have one doubt about the section you linked.

Following the example we have

```julia
struct Point{T}
    x::T
    y::T
end

function norm(p::Point{<:Real})
    sqrt(p.x^2 + p.y^2)
end

```

So if I call norm(Point{Float64}(1.5,2.5)) everything works as expected. But if I declare the function as following

f

```julia
function norm(p::Point{<:Int})
    sqrt(p.x^2 + p.y^2)
end

```

I expect that norm(Point{Float64}(1.5,2.5)) would not work since Float64 is not a subtype of Int.  
Instead it works. Why?

Also in the docs is specified that

```julia
Point{Float64} <: Point{Real}

```

return false event if Float64 \<: Real.

---

<div class="post-metadata">

**Author:** ![goerch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerch/32/29122_2.png) [@goerch](https://discourse.julialang.org/u/goerch)\
**Post date:** [January 31, 2022, 6:29pm UTC](https://discourse.julialang.org/t/dict-subtype-definition/75496/5 "2022-01-31T18:29:36Z")

</div>

Lots of questions

```julia
struct Point{T}
    x::T
    y::T
end

function norm(p::Point{<:Int})
    sqrt(p.x^2 + p.y^2)
end

norm(Point{Float64}(1.5,2.5))

```

results in

```julia
ERROR: LoadError: MethodError: no method matching norm(::Point{Float64})

```

for me. If you try

```julia
struct Point{T}
    x::T
    y::T
end

function norm(p::Point{<:Float64})
    sqrt(p.x^2 + p.y^2)
end
function norm(p::Point{<:Int})
    sqrt(p.x^2 + p.y^2)
end

methods(norm)

```

you’ll see something like

```julia
# 2 methods for generic function "norm":
[1] norm(p::Point{<:Float64}) in Main at ...
[2] norm(p::Point{<:Int64}) in Main at ...

```

And lastly

> [@iskyd](#):
>
> `Point{Float64} <: Point{Real}`

is documented [here](https://docs.julialang.org/en/v1/manual/types/#man-parametric-composite-types).

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [January 31, 2022, 7:15pm UTC](https://discourse.julialang.org/t/dict-subtype-definition/75496/6 "2022-01-31T19:15:46Z")

</div>

> [@iskyd](#):
>
> I expect that norm(Point{Float64}(1.5,2.5)) would not work since Float64 is not a subtype of Int.  
> Instead it works. Why?

It’s probably because you already defined `Point` for `Real`. Defining it for `Int` just adds a new method on top of the old. You can add new methods on top of each other as many times as you like, that is how you use multiple dispatch.

Restart Julia to clear the old method definitions.

BTW, instead of `Point{<:Int}`, just write `Point{Int}`. `Int` and `Float64` have no subtypes, so `<:Int` is just the same as `Int`.
