# Modifying object dict keys

**URL:** https://discourse.julialang.org/t/modifying-object-dict-keys/59266
**Category:** New to Julia
**Tags:** dictionary
**Created:** [April 14, 2021, 10:53am UTC](https://discourse.julialang.org/t/modifying-object-dict-keys/59266 "2021-04-14T10:53:56Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![mkamensky](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkamensky/32/24003_2.png) [@mkamensky](https://discourse.julialang.org/u/mkamensky)
#### Post date: [April 14, 2021, 10:53am UTC](https://discourse.julialang.org/t/modifying-object-dict-keys/59266/1 "2021-04-14T10:53:56Z")

</div>

Hi,

I’m doing

```julia
foo=[1]
bar=Dict(foo => 2)
push!(foo, 3)

```

what I was expecting from the docs is that `bar[[1]]` should be `2`. Instead, the key is not found, and neither is (the new) `foo` or `bar[[1,3]]`. When I print `bar` it seems to think it does have `[1,3]` as a key. Is this the expected behaviour in this case? What would be an efficient way of getting the behaviour I expected?

Thanks

---

<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: [April 14, 2021, 12:14pm UTC](https://discourse.julialang.org/t/modifying-object-dict-keys/59266/2 "2021-04-14T12:14:11Z")

</div>

There is no efficient generic way of obtaining the behavior you want, in no programming language or library whatsoever. The problem is that the dictionary needs to be informed about the mutation, and the key has no way of knowing in what dictionaries it serves as key.

There could be fast APIs where you directly inform the dictionary about an intended key mutation.

Many languages don’t have your observed behavior by virtue of either forbidding mutable keys alltogether (well, duh) or by requiring that the dictionary owns the key (i.e. you cannot extract a mutable shared reference to the key, you always need to go through the dictionary to mutate it; and on insertion, you either create an implicit copy (C++ style unless you jump through std::move contortions) or hand over ownership (Rust style)).

---

<div class="post-metadata">

### Author: ![mkamensky](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkamensky/32/24003_2.png) [@mkamensky](https://discourse.julialang.org/u/mkamensky)
#### Post date: [April 14, 2021, 12:21pm UTC](https://discourse.julialang.org/t/modifying-object-dict-keys/59266/3 "2021-04-14T12:21:22Z")

</div>

Thanks. What I was imagining is that under the hood, Julia computes a hash for the key, and that is the actual key. Then when I mutate the key, the hash changes, but I can still access with the original hash (and therefore with the original value). At any rate, the actual behaviour is pretty strange, should one just assume that the behaviour in this case is undefined?

Just to clarify, the bahaviour I was expecting was having the value for the _original_ key `[1]` defined

---

<div class="post-metadata">

### Author: ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)
#### Post date: [April 14, 2021, 12:42pm UTC](https://discourse.julialang.org/t/modifying-object-dict-keys/59266/4 "2021-04-14T12:42:30Z")

</div>

> [@mkamensky](#):
>
> Just to clarify, the bahaviour I was expecting was having the value for the _original_ key `[1]` defined

The problem is that probably the actual Dict implementation has to deal with hash collisions. So, after hashing the object and searching for the hash, it probably compares the key itself to all keys in that hash bucket (this is, all keys that happen to have the same hash and were stored at that `Dict`) and, in this process, it does not find the original value in the bucket.

---

<div class="post-metadata">

### Author: ![mkamensky](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkamensky/32/24003_2.png) [@mkamensky](https://discourse.julialang.org/u/mkamensky)
#### Post date: [April 14, 2021, 1:04pm UTC](https://discourse.julialang.org/t/modifying-object-dict-keys/59266/5 "2021-04-14T13:04:06Z")

</div>

Thanks, that sounds like a plausible explanation, but still I find the end result peculiar (and inconsistent with the output when printing the dict)

---

<div class="post-metadata">

### Author: ![FPGro](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fpgro/32/20822_2.png) [@FPGro](https://discourse.julialang.org/u/FPGro)
#### Post date: [April 14, 2021, 1:17pm UTC](https://discourse.julialang.org/t/modifying-object-dict-keys/59266/6 "2021-04-14T13:17:52Z")

</div>

The problem with the output is really that you can’t see that the value and it’s hash now mismatch.

That said, you can use other kinds of Dicts. If you can keep the reference to `foo` alive, then an `IdDict` may just do what you want:

```julia
julia> foo = [1]
1-element Vector{Int64}:
 1

julia> bar = IdDict(foo => 2)
IdDict{Vector{Int64}, Int64} with 1 entry:
  [1] => 2

julia> bar[[1]] # does not work in IdDict
ERROR: KeyError: key [1] not found
Stacktrace:
 [1] getindex(d::IdDict{Vector{Int64}, Int64}, key::Any)
   @ Base .\iddict.jl:93
 [2] top-level scope
   @ REPL[3]:1

julia> push!(foo, 3)
2-element Vector{Int64}:
 1
 3

julia> bar[foo] # but this works now
2

```

---

<div class="post-metadata">

### Author: ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)
#### Post date: [April 14, 2021, 2:11pm UTC](https://discourse.julialang.org/t/modifying-object-dict-keys/59266/7 "2021-04-14T14:11:34Z")

</div>

> [@FPGro](#):
>
> `IdDict` may just do what you want

This is one of the ways to solve it, but it seems that, in his case, he ends up mutating the array used for the key, and does not want the mutated array to be able to recover the stored value, but instead any array that compared to equality to the key vector in its original state.

My suggestion would be something like:

```julia
function my_assign(d, v, k)
    if haskey(d, k)
        d[k] = v
    else
        d[deepcopy(k)] = v
    end
end

```

You probably can create a Dict wrapper that has this behavior. I think it is the safest, while not the most performant. The most performant alternative would be code carefully to never mutate keys, or only do so when you do not care about accessing that position in the Dict anymore.

---

<div class="post-metadata">

### Author: ![mkamensky](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkamensky/32/24003_2.png) [@mkamensky](https://discourse.julialang.org/u/mkamensky)
#### Post date: [April 14, 2021, 2:47pm UTC](https://discourse.julialang.org/t/modifying-object-dict-keys/59266/8 "2021-04-14T14:47:08Z")

</div>

Yes, precisely, I wanted `[1]` to always be the same key, no matter how it’s represented internally. I ended up not mutating the `foo`, and instead creating a new copy, as suggested.

---

<div class="post-metadata">

### Author: ![FPGro](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fpgro/32/20822_2.png) [@FPGro](https://discourse.julialang.org/u/FPGro)
#### Post date: [April 14, 2021, 2:53pm UTC](https://discourse.julialang.org/t/modifying-object-dict-keys/59266/9 "2021-04-14T14:53:46Z")

</div>

Just for reference, there are dictionary representations where you can mutate the key and still find it (by the new value). `OrderedCollections: LittleDict` does that. On the negative side, this involves checking all keys in order until a match or no match is found, so these Dicts get really slow with too much entries.

---

<div class="post-metadata">

### Author: ![Henrique\_Becker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/henrique_becker/32/15443_2.png) [@Henrique\_Becker](https://discourse.julialang.org/u/Henrique_Becker)
#### Post date: [April 15, 2021, 2:24pm UTC](https://discourse.julialang.org/t/modifying-object-dict-keys/59266/10 "2021-04-15T14:24:16Z")

</div>

> [@FPGro](#):
>
> `LittleDict` does that. On the negative side, this involves checking all keys in order until a match or no match is found

😅 This kinda challenges my definition of what a Dict is, but I understand that it is called this way, it appears to be a Dict externally no matter how it is implemented internally.
