# Incomplete description of type vector of pairs

**URL:** https://discourse.julialang.org/t/incomplete-description-of-type-vector-of-pairs/82706
**Category:** General Usage
**Tags:** question, inference, type-of-pair
**Created:** [June 13, 2022, 9:13pm UTC](https://discourse.julialang.org/t/incomplete-description-of-type-vector-of-pairs/82706 "2022-06-13T21:13:56Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)
#### Post date: [June 13, 2022, 9:13pm UTC](https://discourse.julialang.org/t/incomplete-description-of-type-vector-of-pairs/82706/1 "2022-06-13T21:13:56Z")

</div>

Why does Julia not fully describe the type of the elements of the pair vector?

shouldn’t it be the union of the types of the individual elements of the vector?

```julia
Pair{Tuple{Char, Int64, Int64}, Float64}
#and
Pair{Tuple{Char, Int64, Int64}, Nothing}

```

```julia
18-element Vector{Pair{Tuple{Char, Int64, Int64}}}:        
 ('p', 1, 2) => 2.5
 ('q', 1, 2) => 2.5
 ('p', 1, 7) => 4.1
 ('q', 1, 7) => nothing
 ('p', 2, 3) => 7.4
 ('q', 2, 3) => 7.4
 ('p', 2, 5) => nothing
 ('q', 2, 5) => 5.6
 ('p', 3, 4) => nothing
 ('q', 3, 4) => nothing
 ('p', 3, 5) => nothing
 ('q', 3, 5) => nothing
 ('p', 4, 1) => nothing
 ('q', 4, 1) => nothing
 ('p', 4, 5) => nothing
 ('q', 4, 5) => nothing
 ('p', 5, 2) => nothing
 ('q', 5, 2) => 3.2

julia> typeof([ (person,pair...)=>person_values(person,pair...) for (person,pair) in
                               Iterators.product(Persons,Pairs)][:])
Vector{Pair{Tuple{Char, Int64, Int64}}} (alias for Array{Pair{Tuple{Char, Int64, Int64}}, 1})

julia> typeof([ (person,pair...)=>person_values(person,pair...) for (person,pair) in
                               Iterators.product(Persons,Pairs)][:][1])
Pair{Tuple{Char, Int64, Int64}, Float64}

julia> typeof([ (person,pair...)=>person_values(person,pair...) for (person,pair) in
                               Iterators.product(Persons,Pairs)][:][4])
Pair{Tuple{Char, Int64, Int64}, Nothing}

```

---

<div class="post-metadata">

### Author: ![Stephen\_Vavasis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stephen_vavasis/32/3389_2.png) [@Stephen\_Vavasis](https://discourse.julialang.org/u/Stephen_Vavasis)
#### Post date: [June 14, 2022, 11:38pm UTC](https://discourse.julialang.org/t/incomplete-description-of-type-vector-of-pairs/82706/2 "2022-06-14T23:38:39Z")

</div>

I am also hoping somebody knowledgeable will answer this question because I have a similar issue. In the proposed revision ([https://github.com/JuliaCollections/DataStructures.jl/pull/787](https://github.com/JuliaCollections/DataStructures.jl/pull/787)) of sorted containers from DataStructures.jl, I rewrote constructors to fully infer types when given untyped collections of pairs, e.g., `SortedDict(Base.Forward, (1=>"a", 2=>7))`. Here is the relevant code:

```julia
function SortedDict(o::Ordering, kv)
    c = collect(kv)
    if eltype(c) <: Pair
        c2 = collect((t.first, t.second) for t in c)
    elseif eltype(c) <: Tuple
        c2 = collect((t[1], t[2]) for t in c)
    else
        throw(ArgumentError("In SortedDict(o,kv), kv should contain either pairs or 2-tuples"))
    end
    SortedDict{eltype(c2).parameters[1], eltype(c2).parameters[2], typeof(o)}(o, c2)
end

```

Notice that this constructor copies the data three times in a row in order to infer the types. The reason that three copies are needed is the following Julia behavior:

```julia
julia> typeof(collect((1=>"a",2=>7)))
Vector{Pair{Int64}} (alias for Array{Pair{Int64}, 1})

```

I could remove at least one of the three copying operations if the above statement returned `Vector{Pair{Int64,Any}}` or `Vector{Pair{Int64, Union{String,Int64}}` instead of the inner type `Pair{Int64}` that has a free parameter.

---

<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: [June 15, 2022, 12:44am UTC](https://discourse.julialang.org/t/incomplete-description-of-type-vector-of-pairs/82706/3 "2022-06-15T00:44:08Z")

</div>

> [@Stephen\_Vavasis](#):
>
> I could remove at least one of the three copying operations if the above statement returned `Vector{Pair{Int64,Any}}` or `Vector{Pair{Int64, Union{String,Int64}}`

Note that neither of those will actually work because julia types are [invariant](https://docs.julialang.org/en/v1/manual/types/#man-parametric-composite-types):

```julia
julia> Pair{Int, String} <: Pair{Int, Any}
false

julia> Pair{Int, String} <: Pair{Int, Union{String, Int}}
false

```

so `collect` won’t return a collection with either of those element types, since a vector of that type can’t hold any of the things you’ve put into it.

The syntax `Pair{Int}` is just a shorthand for the set of all `Pair` types with `Int` as their first parameter:

```julia
julia> Pair{Int} == Pair{Int, T} where T
true

```

(incidentally, I’m surprised that `===` returns false in the above case).

That’s not to say, though, that a `Vector{Pair{Int, Union{Int, String}}}` is an unreasonable thing to want. But constructing one will involve making a new `Pair{Int, Union{...}}` for each element, which is something `collect` isn’t going to do.

---

<div class="post-metadata">

### Author: ![Stephen\_Vavasis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stephen_vavasis/32/3389_2.png) [@Stephen\_Vavasis](https://discourse.julialang.org/u/Stephen_Vavasis)
#### Post date: [June 15, 2022, 1:14am UTC](https://discourse.julialang.org/t/incomplete-description-of-type-vector-of-pairs/82706/4 "2022-06-15T01:14:10Z")

</div>

I agree that `Pair{Int,Int}` is not a subtype of `Pair{Int,Any}`, but I disagree that `Vector{Pair{Int,Any}}` is unsuitable for the requested operation:

```julia
julia> u = Pair{Int,Any}[1=>"a",2=>7]
2-element Vector{Pair{Int64, Any}}:
 1 => "a"
 2 => 7

julia> typeof(u)
Vector{Pair{Int64, Any}} (alias for Array{Pair{Int64, Any}, 1})

julia> push!(u, 3=>9.9)
3-element Vector{Pair{Int64, Any}}:
 1 => "a"
 2 => 7
 3 => 9.9

```

So I still think it would be reasonable (and helpful in my use-case) for `collect` to return `Vector{Pair{Int,Any}}`.

---

<div class="post-metadata">

### Author: ![rocco\_sprmnt21](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rocco_sprmnt21/32/20127_2.png) [@rocco\_sprmnt21](https://discourse.julialang.org/u/rocco_sprmnt21)
#### Post date: [June 15, 2022, 3:50pm UTC](https://discourse.julialang.org/t/incomplete-description-of-type-vector-of-pairs/82706/5 "2022-06-15T15:50:16Z")

</div>

not sure I have fully understood the argument on the functioning of collect in relation to the determination of the types of the elements making up the vector.  
I try to submit two other examples that if clarified I can allow myself to better understand how things are going.

functions derive [this discussion](https://discourse.julialang.org/t/defining-a-parameter-out-of-pairs-and-values/82701/9)

Here the compréhension completely determines the type of the components the dict

```julia
julia> [(p,pp...)=>pv(p,pp) for(p,pp) in Iterators.flatten([k.=>v for (k,v) in d1])]
7-element Vector{Pair{Tuple{Char, Int64, Int64}, Float64}}:
 ('p', 1, 2) => 2.5
 ('p', 1, 7) => 4.1
 ('p', 2, 3) => 7.4
 ('q', 1, 2) => 2.5
 ('q', 2, 3) => 7.4
 ('q', 2, 5) => 5.6
 ('q', 5, 2) => 3.2

```

here not

```julia
ulia> [ (person,pair...)=>pv(person,pair) for (person,pair) in
                               Iterators.product(Persons,Pairs)][:]
18-element Vector{Pair{Tuple{Char, Int64, Int64}}}:
 ('p', 1, 2) => 2.5
 ('q', 1, 2) => 2.5
 ('p', 1, 7) => 4.1
 ('q', 1, 7) => nothing
 ('p', 2, 3) => 7.4
 ('q', 2, 3) => 7.4
 ('p', 2, 5) => nothing
 ('q', 2, 5) => 5.6
 ('p', 3, 4) => nothing
 ('q', 3, 4) => nothing
 ('p', 3, 5) => nothing
 ('q', 3, 5) => nothing
 ('p', 4, 1) => nothing
 ('q', 4, 1) => nothing
 ('p', 4, 5) => nothing
 ('q', 4, 5) => nothing
 ('p', 5, 2) => nothing
 ('q', 5, 2) => 3.2

```

but if I define the dictionary by hand, I get

```julia
julia> Dict(
       ('p', 1, 2) => 2.5,
        ('q', 1, 2) => 2.5,
        ('p', 1, 7) => 4.1,
        ('q', 1, 7) => nothing,
        ('p', 2, 3) => 7.4,
        )
Dict{Tuple{Char, Int64, Int64}, Union{Nothing, Float64}} with 5 entries:
  ('p', 1, 7) => 4.1
  ('q', 1, 7) => nothing
  ('p', 2, 3) => 7.4
  ('p', 1, 2) => 2.5
  ('q', 1, 2) => 2.5

```

---

<div class="post-metadata">

### Author: ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)
#### Post date: [June 15, 2022, 4:28pm UTC](https://discourse.julialang.org/t/incomplete-description-of-type-vector-of-pairs/82706/6 "2022-06-15T16:28:53Z")

</div>

```julia
julia> [('p', 1, 2) => 2.5
        ('q', 1, 2) => 2.5
        ('p', 1, 7) => 4.1
        ('q', 1, 7) => nothing]
4-element Vector{Pair{Tuple{Char, Int64, Int64}, Union{Nothing, Float64}}}:
 ('p', 1, 2) => 2.5
 ('q', 1, 2) => 2.5
 ('p', 1, 7) => 4.1
 ('q', 1, 7) => nothing

```

---

<div class="post-metadata">

### Author: ![Stephen\_Vavasis](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stephen_vavasis/32/3389_2.png) [@Stephen\_Vavasis](https://discourse.julialang.org/u/Stephen_Vavasis)
#### Post date: [June 15, 2022, 9:41pm UTC](https://discourse.julialang.org/t/incomplete-description-of-type-vector-of-pairs/82706/7 "2022-06-15T21:41:55Z")

</div>

Let me just interject: for my own use-case, it would be OK that `collect((1=>"a",2=>7)` returns an object of type `Vector{Pair{Int}}` rather than `Vector{Pair{Int,Any}}` if only I knew of a documented (i.e., likely to persist in future versions of Julia) method to retrieve the types of the inner objects. This snippet illustrates the issue:

```julia
julia> u = Pair{Int,Any}[1=>"a",2=>7]
2-element Vector{Pair{Int64, Any}}:
 1 => "a"
 2 => 7

julia> eltype(u).parameters[1]
Int64

julia> u=collect((1=>"a",2=>7))
2-element Vector{Pair{Int64}}:
 1 => "a"
 2 => 7

julia> eltype(u).parameters[1]
ERROR: type UnionAll has no field parameters
Stacktrace:
 [1] getproperty(x::Type, f::Symbol)
   @ Base .\Base.jl:37
 [2] top-level scope
   @ REPL[39]:1

```
