# Mutating a dictionary through aliases

**URL:** <https://discourse.julialang.org/t/mutating-a-dictionary-through-aliases/86378>\
**Category:** General Usage\
**Tags:** dictionary, accessors\
**Created:** [August 26, 2022, 10:29am UTC](https://discourse.julialang.org/t/mutating-a-dictionary-through-aliases/86378 "2022-08-26T10:29:47Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![danielsoutar](https://avatars.discourse-cdn.com/v4/letter/d/e480ec/32.png) [@danielsoutar](https://discourse.julialang.org/u/danielsoutar)\
**Post date:** [August 26, 2022, 10:29am UTC](https://discourse.julialang.org/t/mutating-a-dictionary-through-aliases/86378/1 "2022-08-26T10:29:47Z")

</div>

Let’s say I have a dictionary like so:

```julia
my_object = Dict{Symbol, Any}(
    :foo => Dict{Symbol, Any}(
        :foo_items => ["item_a", "item_b", "item_c"],
        :bar => Dict{Symbol, Any}(
            :bar_name => ["name_a", "name_b", "name_c"],
            :type_before => ["Float32", "Float64", "String"],
            :type_after => ["Int32", "Int64", "Int8"]
        )
    )
)

```

And I want to convert these arrays, each with different functions, such as making them vectors of `Symbol` rather than `String`. I could mutate this dictionary directly, like this:

```julia
# Need to check these keys are present
if haskey(my_object, :foo)
    if haskey(my_object[:foo], :foo_items)
        my_object[:foo][:foo_items] = Symbol.(my_object[:foo][:foo_items])
    ...
end

```

This however quickly becomes very tedious, with lots of duplication, and is therefore error-prone. I was hoping to use aliasing to make this a bit simpler and more readable, especially because containers like `Dict` are passed by reference:

```julia
if haskey(my_object, :foo)
    foo = my_object[:foo]
    if haskey(foo, :foo_items)
        foo_items = foo[:foo_items]
        foo_items = Symbol.(foo_items)
    ...
end

```

This however does not work, with `my_object` remaining unchanged. Which is strange, because `===` implies that the memory addresses are the same up until the actual change is made:

```julia
julia> foo = my_object[:foo];
julia> foo === my_object[:foo]
true
julia> foo_items = foo[:foo_items];
julia> foo_items === my_object[:foo][:foo_items]
true

```

Is this a case of `copy-on-write`? Why can’t I mutate the dictionary this way? And what can I do instead if I want to mutate elements of a nested dictionary in a simpler way?

---

<div class="post-metadata">

**Author:** ![hendri54](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hendri54/32/9621_2.png) [@hendri54](https://discourse.julialang.org/u/hendri54)\
**Post date:** [August 26, 2022, 12:18pm UTC](https://discourse.julialang.org/t/mutating-a-dictionary-through-aliases/86378/2 "2022-08-26T12:18:55Z")

</div>

> [@danielsoutar](#):
>
> `foo_items = Symbol.(foo_items)`

This creates a new `Vector{Symbol}` and binds the name `foo_items` to it. The link between `foo_items` and `my_object` is now broken.  
In fact, if you check `foo_items === my_object[:foo][:foo_items]` it does return `false` (it returns `true` in your example because you issue `foo_items = foo[:foo_items]` first, which again binds the name `foo_items` to `my_object`).  
To keep `foo_items` pointing to the field in `my_object` you would need `foo_items .= Symbol.(foo_items)`. But that, of course, fails b/c `foo_items` is `Vector{String}`.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [August 26, 2022, 2:02pm UTC](https://discourse.julialang.org/t/mutating-a-dictionary-through-aliases/86378/3 "2022-08-26T14:02:42Z")

</div>

As for cleaner, less repetitive, solutions to your original problem - you may find `Accessors.jl` useful for manipulating nested data structures.  
For example:

```julia
using Accessors

new_obj = @modify(Symbol, my_object[:foo][:foo_items] |> Elements())

```

There is no duplication at all. This assumes that corresponding dict keys exist, though.

---

<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:** [August 26, 2022, 8:32pm UTC](https://discourse.julialang.org/t/mutating-a-dictionary-through-aliases/86378/4 "2022-08-26T20:32:09Z")

</div>

to get a dict with string values transformed into symbols

```julia
setnestval(x::Vector{String}) = Symbol.(x)
setnestval(x) = x

function setnestval(d ::Dict{Symbol, <: Any})
    Dict(map(((k,v),) -> k=>setnestval(v), zip(keys(d),values(d))))
end

julia> d= Dict{Symbol, Any}(
           :foo => Dict{Symbol, Any}(
               :foo_items => ["item_a", "item_b", "item_c"],
               :bar => Dict{Symbol, Any}(
                   :bar_name => ["name_a", "name_b", "name_c"],
                   :type_before => ["Float32", "Float64", "String"],
                   :type_after => ["Int32", "Int64", "Int8"],
                   :type_not_string => [1,2,3]
               )
           )
       )
Dict{Symbol, Any} with 1 entry:
  :foo => Dict{Symbol, Any}(:foo_items=>["item_a", "item_b", "item_c"], :bar=>D…
julia> symd=setnestval(d)
Dict{Symbol, Dict{Symbol, Any}} with 1 entry:
  :foo => Dict(:foo_items=>[:item_a, :item_b, :item_c], :bar=>Dict{Symbol, Vect…
julia> 

julia> 

julia> symd[:foo][:bar]
Dict{Symbol, Vector} with 4 entries:
  :type_not_string => [1, 2, 3]
  :type_before => [:Float32, :Float64, :String]
  :bar_name => [:name_a, :name_b, :name_c]
  :type_after => [:Int32, :Int64, :Int8]

```

---

<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:** [August 26, 2022, 8:40pm UTC](https://discourse.julialang.org/t/mutating-a-dictionary-through-aliases/86378/5 "2022-08-26T20:40:28Z")

</div>

the mutating form

```julia
setnestva!(x::Vector{String}) = Symbol.(x)
setnestval!(x) = x

setnestval!(d ::Dict{Symbol, <: Any}) = map(((k,v),) -> d[k]=setnestval(v), zip(keys(d),values(d)))

setnestval!(d)

```
