# AbstractVector{\<:Pair} and AbstractDict

**URL:** <https://discourse.julialang.org/t/abstractvector-pair-and-abstractdict/8725>\
**Category:** Internals & Design\
**Created:** [February 1, 2018, 3:53am UTC](https://discourse.julialang.org/t/abstractvector-pair-and-abstractdict/8725 "2018-02-01T03:53:48Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![amellnik](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/amellnik/32/137_2.png) [@amellnik](https://discourse.julialang.org/u/amellnik)\
**Post date:** [February 1, 2018, 3:53am UTC](https://discourse.julialang.org/t/abstractvector-pair-and-abstractdict/8725/1 "2018-02-01T03:53:48Z")

</div>

This was discussed some on slack and I wanted to capture it in a more permanent place.

HTTP is now using an `Array{Pair{String,String},1}` to store headers for performance reasons, but for many use cases (like Mux) people would like to read headers without needing to search through an array of pairs.

@oxinabox mentioned the possibility of defining `Base.getindex(xs::AbstractVector{Pair{T, V}}, key) where T<:Union{Symbol, AbstractString}, V` so that these could be indexed like `headers["Origin"]` and similar. @andyferris suggested a lightweight `AbstractDict` wrapper over `AbstractVector{<:Pair}`.

What’s the best option?

---

<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:** [February 1, 2018, 4:38am UTC](https://discourse.julialang.org/t/abstractvector-pair-and-abstractdict/8725/2 "2018-02-01T04:38:17Z")

</div>

What would

```julia
getindex([3 => 1, 2 => 2, 1 => 3], 1)

```

do? A wrapper might be a better option.

**EDIT** sorry I missed `T<:Union{Symbol, AbstractString}`. Re-consider the example with a `NamedArray` or something similar. I still think it is too clever to special case generic accessors for a restricted set of types.

---

<div class="post-metadata">

**Author:** ![oxinabox](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oxinabox/32/206603_2.png) [@oxinabox](https://discourse.julialang.org/u/oxinabox)\
**Post date:** [February 1, 2018, 2:56pm UTC](https://discourse.julialang.org/t/abstractvector-pair-and-abstractdict/8725/3 "2018-02-01T14:56:26Z")

</div>

I agree.

---

<div class="post-metadata">

**Author:** ![jameson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jameson/32/23_2.png) [@jameson](https://discourse.julialang.org/u/jameson)\
**Post date:** [February 1, 2018, 5:19pm UTC](https://discourse.julialang.org/t/abstractvector-pair-and-abstractdict/8725/4 "2018-02-01T17:19:47Z")

</div>

just a thought:

```julia
headers = sort!(["Origin" => "abc", "Content-Type" => "def", "H" => "1", "H" => "2", "H" => "3"])
firstH = searchsortedfirst(headers, "H" => "")
while firstH <= endof(headers) && headers[firstH].first == "H"
    println(headers[firstH].second)
    global firstH += 1
end

```

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [February 1, 2018, 6:25pm UTC](https://discourse.julialang.org/t/abstractvector-pair-and-abstractdict/8725/5 "2018-02-01T18:25:36Z")

</div>

What about

```julia
struct As_assoc end
const as_assoc = As_assoc()

Base.getindex(xs::AbstractVector{Pair{T, V}}, ::As_assoc, key::T) = ...

```

allowing for `headers[as_assoc, "Origin"]` or maybe (needing an extra definition) `headers[as_assoc, :Origin]`.

Re sorting: Losing the order of headers (as seen on the wire) does not seem like a good idea. But it might be a good idea to sort and also store the on-wire order.

---

<div class="post-metadata">

**Author:** ![jameson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jameson/32/23_2.png) [@jameson](https://discourse.julialang.org/u/jameson)\
**Post date:** [February 2, 2018, 8:49pm UTC](https://discourse.julialang.org/t/abstractvector-pair-and-abstractdict/8725/6 "2018-02-02T20:49:07Z")

</div>

> [@foobar\_lv2](#):
>
> Losing the order of headers

Agreed, although the default `sort!` call is a stable-sort, so it can at least preserve the order of any given repeated header. We could preserve the original array too though:

```julia
> view(headers, sortperm(headers, by=first))
> searchsorted(ans, "H" => "", by=first)
2:4

```

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [February 3, 2018, 12:09am UTC](https://discourse.julialang.org/t/abstractvector-pair-and-abstractdict/8725/7 "2018-02-03T00:09:20Z")

</div>

Why not store something like `Vector{Triple{key_T, val_T, Pair{UInt32, UInt32}}}` where the last two denote the offset of the first byte and the last byte of the header line, relative to the start of the request? I almost said `UInt16`, but apparently longer leaders are technically valid HTTP (or may at least be seen in the wild).

That way you can binary search for specific headers and still don’t lose any info (e.g. you probably need to case-normalize header-names anyway; sure convenient if one can look up the on-the-wire spelling in the original header if needed). I know that I would curse if any info were discarded and I needed to reproduce the same interpretation of some malformed HTTP as some weird old or custom piece of software (or wanted to script some adversarial fingerprinting).

But you’re of course right that preserving the order of repeated headers is most important, and these are AFAIK technically the only parts of the order that MUST be preserved according to `rfc7230`.
