# Dynamically defining a struct with default values

**URL:** https://discourse.julialang.org/t/dynamically-defining-a-struct-with-default-values/106855
**Category:** General Usage
**Tags:** macros, metaprogramming, struct
**Created:** [November 28, 2023, 5:27pm UTC](https://discourse.julialang.org/t/dynamically-defining-a-struct-with-default-values/106855 "2023-11-28T17:27:04Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![Titas22](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/titas22/32/39209_2.png) [@Titas22](https://discourse.julialang.org/u/Titas22)
#### Post date: [November 28, 2023, 5:27pm UTC](https://discourse.julialang.org/t/dynamically-defining-a-struct-with-default-values/106855/1 "2023-11-28T17:27:04Z")

</div>

Hi,

I would like to be able to define a struct with some default values based on an input `Dict`.

The input is something like this:

```julia
d = Dict("A"=>1, "B"=>2, "C"=>"x", "D"=>[1,2])

```

And I would like to define a struct like below:

```julia
@kwdef struct MyStruct3
	A::Int64 = 1
	B::Int64 = 2
	C::String = "x"
        D::Vector{Int64} = [1,2]
end

```

I’ve got to a point where I can create a struct with type:

```julia
macro make_struct(name, dict)
	symbols=[:($(Symbol(k))::$(typeof(v))) for (k, v) in eval(dict)]
	:(@kwdef struct $(esc(name))
    	$(map(esc,symbols)...)
    end)
end

@make_struct test d

```

But am not sure how to add default values to that, when I tried this:

```julia
macro make_struct(name, dict)
	symbols=[:($(Symbol(k))::$(typeof(v))=$(v)) for (k, v) in eval(dict)]
	:(@kwdef struct $(esc(name))
    	$(map(esc,symbols)...)
    end)
end

```

I got the following error:

```julia
Expr[:(B::Int64 = 2), :(A::Int64 = 1), :(C::String = "x"), :(D::Vector{Int64} = [1, 2])]
ERROR: syntax: "B::Int64 = 2" inside type definition is reserved around util.jl:589
Stacktrace:
 [1] top-level scope
   @ REPL[149]:1

```

---

<div class="post-metadata">

### Author: ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)
#### Post date: [November 28, 2023, 7:26pm UTC](https://discourse.julialang.org/t/dynamically-defining-a-struct-with-default-values/106855/3 "2023-11-28T19:26:16Z")

</div>

Here, I would not use a macro as the code cannot be generated at compile time and you will have to call `eval` at runtime anyways. The following function works for me:

```julia
function def_dyn_struct(name::Symbol, spec::Dict)
    fields = [:($(Symbol(k))::$(typeof(v)) = $(v)) for (k, v) in spec]
    @eval @kwdef struct $(name)
        $(fields...)
    end
end

```

Your error seems to be related to the fact that `A::Int64 = 1` is not valid inside a normal `struct` definition:

```julia
julia> struct Hu
           A::Int64 = 1
       end
ERROR: syntax: "A::Int64 = 1" inside type definition is reserved around REPL[39]:1

```

Further, when evaluating the code, I guess that `esc` is unnecessary (and also not handled gracefully by `@kwdef`):

```julia
julia> let name = :Ha
           @eval @kwdef struct $(esc(name)) end
       end
ERROR: syntax: invalid type signature around util.jl:589

```

---

<div class="post-metadata">

### Author: ![Titas22](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/titas22/32/39209_2.png) [@Titas22](https://discourse.julialang.org/u/Titas22)
#### Post date: [November 28, 2023, 7:43pm UTC](https://discourse.julialang.org/t/dynamically-defining-a-struct-with-default-values/106855/4 "2023-11-28T19:43:18Z")

</div>

> [@Titas22](#):
>
> `d = Dict("A"=>1, "B"=>2, "C"=>"x", "D"=>[1,2])`

Legend! Yeah that works for me - thanks 👌

---

<div class="post-metadata">

### Author: ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)
#### Post date: [November 28, 2023, 8:09pm UTC](https://discourse.julialang.org/t/dynamically-defining-a-struct-with-default-values/106855/5 "2023-11-28T20:09:07Z")

</div>

Glad you have a solution. FWIW, if you ever wanted full dynamism, NamedTuples are the way to get it. Something like

```julia
struct Flexible{NT}
    fields::NT
end
mk_struct_constructor(dict::Dict) = mk_struct_constructor(NamedTuple(dict))
Base.getproperty(f::Flexible, field) = getproperty(f.fields, field)
function mk_struct_constructor(nt::NamedTuple)
    constructor(; kwargs...) = Flexible(merge(nt, NamedTuple(kwargs)))
end

```

then

```julia
julia> MyStruct3 = mk_struct_constructor(Dict(:A=>2))
(::var"#constructor#7"{var"#constructor#6#8"{NamedTuple{(:A,), Tuple{Int64}}}}) (generic function with 1 method)

julia> MyStruct3()
Flexible{NamedTuple{(:A,), Tuple{Int64}}}((A = 2,))

julia> MyStruct3(A=5)
Flexible{NamedTuple{(:A,), Tuple{Int64}}}((A = 5,))

```

This won’t face the world-age issues you’d have with the previous solution, and it’s AFAIK just as efficient as a normal struct.
