# Unpack named tuples (does anyone know how to do it?)

**URL:** <https://discourse.julialang.org/t/unpack-named-tuples-does-anyone-know-how-to-do-it/32456>\
**Category:** General Usage\
**Created:** [December 18, 2019, 10:15pm UTC](https://discourse.julialang.org/t/unpack-named-tuples-does-anyone-know-how-to-do-it/32456 "2019-12-18T22:15:44Z")\
**Posts on this page:** 1\
**Showing post:** 13

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [June 14, 2020, 5:16am UTC](https://discourse.julialang.org/t/unpack-named-tuples-does-anyone-know-how-to-do-it/32456/13 "2020-06-14T05:16:39Z")

</div>

I started thinking about this recently after seeing [this thread](https://discourse.julialang.org/t/with-struct-do/41341/7). I mostly agree with @Tamas_Papp that a struct is likely the best solution, however I think these sorts of code transformations are interesting to think about.

Basically, what would be needed to do this is a macro that knows about type information. Base Julia does not have such a construct, but IRTools.jl sorta does with it’s `@dynamo`.

Here is a dynamo I call `with` that in some senses will behave like `@unpack`, even on a named Tuple:

```julia
using IRTools: IRTools, @dynamo, @code_ir, postwalk, prewalk, IR, argument!, 
using IRTools: xcall, var, insertafter!, isexpr, branches, blocks
using Setfield: @set

@dynamo function with(f, obj)
    ir = IR(f)
    objarg = argument!(ir)
    d = Dict()
    for fn ∈ reverse(fieldnames(obj))
        d[fn] = insertafter!(ir, var(1), xcall(:getfield, objarg, QuoteNode(fn)))
    end

    function replacer(x)
        if x isa GlobalRef && x.name ∈ fieldnames(obj)
            d[x.name]
        else
            x
        end
    end

    for (n, st) ∈ ir
        ir[n] = prewalk(replacer, st)
    end

    for blck ∈ blocks(ir)
        bs = branches(blck)
        for i ∈ eachindex(bs)
            b = bs[i]
            bs[i] = @set b.condition = postwalk(replacer, b.condition)
            for j ∈ eachindex(bs[i].args) 
                bs[i].args[j] = postwalk(replacer, bs[i].args[j])
            end
        end
        ir
    end
    ir
end

```

Apologies for the spaghetti code, I’m not yet very skilled with writing IR. Here’s `with` in action:

```julia
julia> nt = (;a=1, b=4.0, c="hi", d=true)
(a = 1, b = 4.0, c = "hi", d = true)

julia> with(nt) do
           if !d
               (a - b)/(a + b)
           else
               c
           end
       end
"hi"

```

This is a rather brittle solution that has many weaknesses.

For instance, if there’s a local variable available named `d`, then `d` won’t get replaced with `nt.d`:

```julia
julia> let
           nt = (;a=1, b=4.0, c="hi", d=true)
           d = false
           with(nt) do
               if !d
                   (a - b)/(a + b)
               else
                   c
               end
           end
       end
-0.6

```

I’m sure there are other problems and corner cases, but I learned a lot writing this so I thought I’d share.

---

_[View the full topic](https://discourse.julialang.org/t/unpack-named-tuples-does-anyone-know-how-to-do-it/32456)._
