# Proper way to make an empty sizehinted Dict

**URL:** <https://discourse.julialang.org/t/proper-way-to-make-an-empty-sizehinted-dict/50962>\
**Category:** General Usage\
**Tags:** question\
**Created:** [November 29, 2020, 8:59pm UTC](https://discourse.julialang.org/t/proper-way-to-make-an-empty-sizehinted-dict/50962 "2020-11-29T20:59:37Z")\
**Posts on this page:** 2\
**Page:** 1

<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:** [November 29, 2020, 8:59pm UTC](https://discourse.julialang.org/t/proper-way-to-make-an-empty-sizehinted-dict/50962/1 "2020-11-29T20:59:37Z")

</div>

I have an application where it seems appropriate to have a `Dict` effectively containing a large number of lightly wrapped `Dict` containers. Say something like, `d = Dict{Int64,Dict{Int64,Int128}}()`, where the indices of `d` can be pre-computed and the number of elements the inner dictionaries can be approximated, with approximations depending on the indices. I would like to initialize `d` by applying `sizehint!` to the inner dictionaries, so I could do something like this:

```julia
approx(i)=isqrt(i)
s=Set(6:7:400000)
init1(s) = Dict{Int64,Dict{Int64,Int128}}( i=>sizehint!(Dict{Int64,Int128}(),approx(i)) for i in s)

```

but I noticed that even though `sizehint!` on an empty `Dict` breaks out of its `rehash!` early, it still ends up resizing its `slots`, `keys`, and `vals` fields, which often need to be reallocated in this case. I can avoid the extra allocations by using the 8-argument inner constructor of `Dict{K,V}`, but need to refer to `Base._tablesz()`, to make sure I size things appropriately.

```julia
function init2(s)
    d=Dict{Int64,Dict{Int64,Int128}}()
    sizehint!(d,length(s))
    for i in s
        n = Base._tablesz(approx(i)) 
        d[i] = Dict{Int64,Int128}(zeros(UInt8,n), Vector{Int64}(undef,n), Vector{Int128}(undef,n), 0, 0, 0, 1, 0)
    end
    return d
end

```

This gives me a noticeable speed improvement for this part of the operation.

```julia
using BenchmarkTools
@btime init1($s) # 243.783 ms (399914 allocations: 925.18 MiB)
@btime init2($s) # 175.247 ms (228585 allocations: 900.58 MiB)

```

but feels, dirty, since `Base._tablesz()` doesn’t seem to be something I should be relying on. Is there a reason we couldn’t have

```julia
function Dict{K,V}(sh::Int64) where {K,V}
    n = _tablesz(sh)
    Dict{K,V}(zeros(UInt8,n), Vector{K}(undef, n), Vector{V}(undef, n), 0, 0, 0, 1, 0)
end

```

or something like that as an inner constructor? It seems like the `Dict{K,V}(ps::Pair...)` method would benefit from this.

Alternatively is there a better way to initialize a `Dict` when I know the size?

---

<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 1, 2020, 2:03am UTC](https://discourse.julialang.org/t/proper-way-to-make-an-empty-sizehinted-dict/50962/2 "2020-12-01T02:03:13Z")

</div>

The best solution I’ve encountered so far is to refactor, so a new type `EmptyDict` isolates all the dealings with the internals of `Dict`.

```julia
""" A wrapper for directly constructing a Dict{K,V} with a sizehint """
struct EmptyDict{K,V} end
function EmptyDict{K,V}(n::Integer) where {K,V}
    n=Base._tablesz(n)
    Dict{K,V}(zeros(UInt8,n), Vector{K}(undef, n), Vector{V}(undef, n), 0, 0, 0, 1, 0)
end

```

Then I can write `init3` with the speed and allocation savings of `init2`, but the clean syntax of `init1`.

```julia
init3(s) = Dict{Int64,Dict{Int64,Int128}}( i=>EmptyDict{Int64,Int128}(approx(i)) for i in s)

```
