# Macro to create struct problem

**URL:** <https://discourse.julialang.org/t/macro-to-create-struct-problem/86737>\
**Category:** General Usage\
**Created:** [September 3, 2022, 5:49pm UTC](https://discourse.julialang.org/t/macro-to-create-struct-problem/86737 "2022-09-03T17:49:07Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Jakub\_Mitura](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakub_mitura/32/19496_2.png) [@Jakub\_Mitura](https://discourse.julialang.org/u/Jakub_Mitura)\
**Post date:** [September 3, 2022, 5:49pm UTC](https://discourse.julialang.org/t/macro-to-create-struct-problem/86737/1 "2022-09-03T17:49:08Z")

</div>

Hello for compatibility with other library I need to create a struct with names of the fields supplied via list of Strings

I tried sth like this

```julia
structName="example_struct"
keyss= ["a","b","c"]
symbolKeys= map(key->Symbol(key),keyss )

macro make_struct(struct_name, fields)
    esc(quote struct $struct_name
        $(fields...)
        end
    end)
end
println(@macroexpand @make_struct(structName,symbolKeys))
eval(@make_struct(structName,symbolKeys))

```

I based the code on [Trouble understanding macros: creating a struct on the fly](https://discourse.julialang.org/t/trouble-understanding-macros-creating-a-struct-on-the-fly/4576)

Still I get error

```julia
 MethodError: no method matching iterate(::Symbol)

```

What am I doing wrong?

---

<div class="post-metadata">

**Author:** ![pdeffebach](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pdeffebach/32/10320_2.png) [@pdeffebach](https://discourse.julialang.org/u/pdeffebach)\
**Post date:** [September 3, 2022, 7:27pm UTC](https://discourse.julialang.org/t/macro-to-create-struct-problem/86737/2 "2022-09-03T19:27:01Z")

</div>

A macro takes in the _expression_ it’s given. It knows nothing about what `keys` actually is. So you when you try to splat the ` $(fields...)`, you are splatting `:symbolKeys`, which is what’s passed to the macro.

In general you cannot automatically generate a struct like this with a macro. You can only give a macro expressions and return expressions. Nothing which actually acts on what the expression represents.

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [September 3, 2022, 8:30pm UTC](https://discourse.julialang.org/t/macro-to-create-struct-problem/86737/3 "2022-09-03T20:30:58Z")

</div>

In this case, you’re probably looking for plain `eval` (or `@eval`): this is the way to take _values_ and generate (and evaluate) _code_.

```julia
struct_name = "example_struct"
fields = ["a","b","c"]

@eval begin
    struct $(Symbol(struct_name))
        $(Symbol.(fields)...)
    end
end

```

---

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [September 3, 2022, 9:03pm UTC](https://discourse.julialang.org/t/macro-to-create-struct-problem/86737/4 "2022-09-03T21:03:50Z")

</div>

> [@Jakub\_Mitura](#):
>
> for compatibility with other library I need to create a struct with names of the fields supplied via list of Strings

Can you describe your problem in a little more detail? We might be able to recommend a different approach.

---

<div class="post-metadata">

**Author:** ![Jakub\_Mitura](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakub_mitura/32/19496_2.png) [@Jakub\_Mitura](https://discourse.julialang.org/u/Jakub_Mitura)\
**Post date:** [September 4, 2022, 4:11am UTC](https://discourse.julialang.org/t/macro-to-create-struct-problem/86737/5 "2022-09-04T04:11:59Z")

</div>

Thank You all for help! As to describing problem in more detail I want to automate definitions of some functions for automatic differentiation (there will be limited number of them like 6-7 - but the code is very repetitive). All information (conff\_params below) will be constant and manually provided in a code - known at compilation time it requires:

1. define set of variables definitions and for each weather it is parameter,state,output or input; additionally I pass the kernel function (testKern below) that has the same arguments and is the function I want to differentiate (conff\_params below)
2. need to create struct that is inheriting from Lux.AbstractExplicitLayer (KernelAstr below)
3. define function that call Enzyme.autodiff\_deferred (testKernDeff below)
4. define ChainRulesCore.rrule (ChainRulesCore.rrule(::typeof(calltestKern) below)
5. define Lux.initialparameters (Lux.initialparameters below)
6. define Lux.initialstates (Lux.initialstates below)
7. define apply function of the layer ((l::KernelAstr)(x, ps, st::NamedTuple) below)
8. define call function using CUDA macro (calltestKern below)

all steps can be done using information supplied in variables list list (conff\_params below)

How variables are defined

```julia
@enum paramType Eparameter=1 Estate Einput Eoutput

conff_params= Dict(
                "A"=>(Einput
                    ,(rng,l)->()  
                    ,Duplicated
                     )
                ,"p"=>(Eparameter
                ,(rng,l)->CuArray(rand(rng,Float32, l.confA, l.confA, l.confA))
                ,Duplicated
                )
                ,"Aout"=>(Eoutput
                    ,(rng,l)->()  
                    ,Duplicated
                    )
                ,"Nxa"=>(
                    Estate
                    ,(rng,l)->Nx
                    ,Const
                    )
                ,"Nya"=>(
                    Estate
                    ,(rng,l)->Ny
                    ,Const
                    )
                ,"Nza"=>(
                    Estate
                    ,(rng,l)->Nz
                    ,Const
                    )
                )

```

example code before metaprogramming

```julia

#lux layers from http://lux.csail.mit.edu/dev/manual/interface/
struct KernelAstr<: Lux.AbstractExplicitLayer
    confA::Int
    Nxa::Int
    Nya::Int
    Nza::Int
end

function testKern(A, p, Aout,Nxa,Nya,Nza)
    #adding one bewcouse of padding
    x = (threadIdx().x + ((blockIdx().x - 1) * CUDA.blockDim_x())) + 1
    y = (threadIdx().y + ((blockIdx().y - 1) * CUDA.blockDim_y())) + 1
    z = (threadIdx().z + ((blockIdx().z - 1) * CUDA.blockDim_z())) + 1
    Aout[x, y, z] = A[x, y, z] *p[x, y, z] *p[x, y, z] *p[x, y, z] 
    
    return nothing
end

function testKernDeff( A, dA, p
    , dp, Aout
    , dAout,Nxa,Nya,Nza)
    Enzyme.autodiff_deferred(testKern, Const, Duplicated(A, dA), Duplicated(p, dp), Duplicated(Aout, dAout),Const(Nxa),Const(Nya),Const(Nza))
    return nothing
end

function calltestKern(A, p,Nxa,Nya,Nza)
    Aout = CUDA.zeros(Nx+totalPad, Ny+totalPad, Nz+totalPad ) 
    @cuda threads = threads blocks = blocks testKern( A, p, Aout,Nxa,Nya,Nza)
    return Aout
end

aa=calltestKern(A, p,Nx,Ny,Nz)
maximum(aa)

# rrule for ChainRules.
function ChainRulesCore.rrule(::typeof(calltestKern), A, p,Nxa,Nya,Nza)
    Aout = calltestKern(A, p,Nxa,Nya,Nza)#CUDA.zeros(Nx+totalPad, Ny+totalPad, Nz+totalPad )
    function call_test_kernel1_pullback(dAout)
        # Allocate shadow memory.
        threads = (4, 4, 4)
        blocks = (2, 2, 2)
        dp = CUDA.ones(size(p))
        dA = CUDA.ones(size(A))
        @cuda threads = threads blocks = blocks testKernDeff( A, dA, p, dp, Aout, CuArray(collect(dAout)),Nxa,Nya,Nza)

        f̄ = NoTangent()
        x̄ = dA
        ȳ = dp
        
        return f̄, x̄, ȳ,NoTangent(),NoTangent(),NoTangent()
    end   
    return Aout, call_test_kernel1_pullback

end
#first testing
# ress=Zygote.jacobian(calltestKern,A, p ,Nx,Ny,Nz)
# typeof(ress)
# maximum(ress[1])
# maximum(ress[2])

function KernelA(confA::Int,Nxa,Nya,Nza)
    return KernelAstr(confA,Nxa,Nya,Nza)
end

function Lux.initialparameters(rng::AbstractRNG, l::KernelAstr)
    return (paramsA=CuArray(rand(rng,Float32, l.confA, l.confA, l.confA))
    ,paramsB = CuArray(rand(rng,Float32, l.Nxa, l.Nya, l.Nza)))
end

Lux.initialstates(::AbstractRNG, ::KernelAstr) = (Nxa=Nx,Nya=Ny,Nza=Nz)

# # But still recommened to define these
# Lux.parameterlength(l::KernelAstr) = l.out_dims * l.in_dims + l.out_dims

# Lux.statelength(::KernelAstr) = 0

function (l::KernelAstr)(x, ps, st::NamedTuple)
    return calltestKern(x, ps.paramsA,st.Nxa,st.Nya,st.Nza),st
end

```

---

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [September 4, 2022, 4:24am UTC](https://discourse.julialang.org/t/macro-to-create-struct-problem/86737/6 "2022-09-04T04:24:23Z")

</div>

Ok, in that case I think the answer from @ffevotte is what you are looking for. You can put an `@eval` inside a `for` loop if the code that you’re generating is repetitive. However, there is a tradeoff. I think `for` loops with `@eval` are harder to read than just writing the code out by hand. Also, this kind of thing confuses the VS Code linter, so you won’t get correct linting for other parts of the code that use the generated types and functions. (Maybe that will be fixed in the future, but it seems like a tricky issue to fix in the linter.)

See this section of the manual for a discussion of code generation:

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