# Using macros to explode a struct into a tuple of its members

**URL:** <https://discourse.julialang.org/t/using-macros-to-explode-a-struct-into-a-tuple-of-its-members/58997>\
**Category:** General Usage\
**Created:** [April 10, 2021, 5:36pm UTC](https://discourse.julialang.org/t/using-macros-to-explode-a-struct-into-a-tuple-of-its-members/58997 "2021-04-10T17:36:50Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![Andrea\_Vigliotti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andrea_vigliotti/32/7635_2.png) [@Andrea\_Vigliotti](https://discourse.julialang.org/u/Andrea_Vigliotti)\
**Post date:** [April 10, 2021, 5:36pm UTC](https://discourse.julialang.org/t/using-macros-to-explode-a-struct-into-a-tuple-of-its-members/58997/1 "2021-04-10T17:36:50Z")

</div>

So, I would like use a macro to convert a `struct` into a tuple of its members

let `boo` be the following

```julia
struct boo 
  a
  b
  c
end

```

and `collect` defined as follows

```julia
macro collect(x)
  :( tuple($x.a,$x.b,$x.c) )
end

```

```
@collect (macro with 1 method)

```

things seem to work if invoked from the REPL

```julia
P = boo(1,2,3)
@collect P

```

```
(1, 2, 3)

```

but if the macro is invoked within a function or within a `let` block I get the following error

```julia
let y = P
  @collect y
end

```

```
UndefVarError: y not defined

Stacktrace:

 [1] top-level scope at In[6]:2

 [2] include_string(::Function, ::Module, ::String, ::String) at ./loading.jl:1091

```

I must defintitely be missing something essential about macros, can anyone please help me to understand what am I doing wrong here,

many thanks in advance!  
Andrea

---

<div class="post-metadata">

**Author:** ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)\
**Post date:** [April 10, 2021, 5:46pm UTC](https://discourse.julialang.org/t/using-macros-to-explode-a-struct-into-a-tuple-of-its-members/58997/2 "2021-04-10T17:46:08Z")

</div>

You need to escape `x` inside the macro with `esc(x)`, this is also explained in the manual on macro hygiene:

[https://docs.julialang.org/en/v1/manual/metaprogramming/#Hygiene](https://docs.julialang.org/en/v1/manual/metaprogramming/#Hygiene)

Note that in this particular example, there is not really a reason to prefer a macro over a regular function. Functions OTOH, are a lot more composable than macros, so it is generally better to avoid macros for things that can be done in a function.

---

<div class="post-metadata">

**Author:** ![Andrea\_Vigliotti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andrea_vigliotti/32/7635_2.png) [@Andrea\_Vigliotti](https://discourse.julialang.org/u/Andrea_Vigliotti)\
**Post date:** [April 10, 2021, 5:48pm UTC](https://discourse.julialang.org/t/using-macros-to-explode-a-struct-into-a-tuple-of-its-members/58997/3 "2021-04-10T17:48:55Z")

</div>

many thanks! I will look that up!  
the reason for using macros here is on one hand to experiment, on the other hand I thought it might be faster since macros are substituted before compile, so there is really no overhead due to argument passing etc.

---

<div class="post-metadata">

**Author:** ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)\
**Post date:** [April 10, 2021, 6:00pm UTC](https://discourse.julialang.org/t/using-macros-to-explode-a-struct-into-a-tuple-of-its-members/58997/4 "2021-04-10T18:00:19Z")

</div>

The macro is just generating the code `tuple(y.a, y.b, y.c)`, which will then still have to be run at runtime, so it won’t be any faster than a function.

---

<div class="post-metadata">

**Author:** ![Andrea\_Vigliotti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andrea_vigliotti/32/7635_2.png) [@Andrea\_Vigliotti](https://discourse.julialang.org/u/Andrea_Vigliotti)\
**Post date:** [April 10, 2021, 6:06pm UTC](https://discourse.julialang.org/t/using-macros-to-explode-a-struct-into-a-tuple-of-its-members/58997/5 "2021-04-10T18:06:07Z")

</div>

I got it to work in this fashion,

```julia
macro collect(x)
  :($(esc(:($x.a, $x.b, $x.c))))
end

```

```
@collect (macro with 1 method)

```

```julia
P = boo(1,2,3)
a,b,c = @collect P

```

```
(1, 2, 3)

```

```julia
a,b,c = let y = P
  @collect y
end

```

```
(1, 2, 3)

```

but I definitely need to ponder it some more.

you are probably right about speed, but I also wanted to give macros a try

many thanks again!  
Andrea

---

<div class="post-metadata">

**Author:** ![marius311](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marius311/32/3953_2.png) [@marius311](https://discourse.julialang.org/u/marius311)\
**Post date:** [April 10, 2021, 8:18pm UTC](https://discourse.julialang.org/t/using-macros-to-explode-a-struct-into-a-tuple-of-its-members/58997/6 "2021-04-10T20:18:06Z")

</div>

Note that you can do this with a generated function which will be just as fast as the macro version and usable on any type:

```julia
julia> @generated fieldvalues(x) = Expr(:tuple, (:(x.$f) for f=fieldnames(x))...)

julia> P = boo(1,2,3);

julia> fieldvalues(P)
(1,2,3)

```

If you look at e.g.

```julia
@code_llvm (P -> (a,b,c = fieldvalues(P)))(P)
@code_llvm (P -> (a,b,c = @collect(P)))(P)

```

you can confirm the LLVM code is identical between the generated function and the macro so its just as fast.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [April 11, 2021, 12:25am UTC](https://discourse.julialang.org/t/using-macros-to-explode-a-struct-into-a-tuple-of-its-members/58997/7 "2021-04-11T00:25:22Z")

</div>

See also [this discourse thread](https://discourse.julialang.org/t/get-fieldnames-and-values-of-struct-as-namedtuple/8991), which discussed conversion to a `NamedTuple` and also recommended a generated function.

---

<div class="post-metadata">

**Author:** ![Andrea\_Vigliotti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andrea_vigliotti/32/7635_2.png) [@Andrea\_Vigliotti](https://discourse.julialang.org/u/Andrea_Vigliotti)\
**Post date:** [April 11, 2021, 3:36pm UTC](https://discourse.julialang.org/t/using-macros-to-explode-a-struct-into-a-tuple-of-its-members/58997/8 "2021-04-11T15:36:36Z")

</div>

this is very nice, thanks! Did not know about generated functions.

---

<div class="post-metadata">

**Author:** ![Andrea\_Vigliotti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andrea_vigliotti/32/7635_2.png) [@Andrea\_Vigliotti](https://discourse.julialang.org/u/Andrea_Vigliotti)\
**Post date:** [April 11, 2021, 3:37pm UTC](https://discourse.julialang.org/t/using-macros-to-explode-a-struct-into-a-tuple-of-its-members/58997/9 "2021-04-11T15:37:46Z")

</div>

thanks, I’ll look into that. I need to learn more about the metaprogramming side of Julia.
