# Anonymous nested struct

**URL:** <https://discourse.julialang.org/t/anonymous-nested-struct/33723>\
**Category:** Internals & Design\
**Created:** [January 24, 2020, 2:45am UTC](https://discourse.julialang.org/t/anonymous-nested-struct/33723 "2020-01-24T02:45:54Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![Sijun](https://avatars.discourse-cdn.com/v4/letter/s/b2d939/32.png) [@Sijun](https://discourse.julialang.org/u/Sijun)\
**Post date:** [January 24, 2020, 2:45am UTC](https://discourse.julialang.org/t/anonymous-nested-struct/33723/1 "2020-01-24T02:45:54Z")

</div>

By “Anonymous nested struct” I mean defining a struct that has another struct with no name inside:

```julia
struct ABC
    name::String
    data::struct
        raw::Vector{Float64}
        value::Int
    end
end

```

I wonder such a concept is under discussion among Julia designers.

I believe allowing anonymous nested struct should make life much easier and make code more readable compared to these:

```julia
struct ABC
    name::String
    data::Tuple{Vector{Float64}, Int}
end

```

or

```julia
struct Data
    raw::Vector{Float64}
    value::Int
end

struct ABC
    name::String
    data::Data
end
``
```

---

<div class="post-metadata">

**Author:** ![jonniedie](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jonniedie/32/12842_2.png) [@jonniedie](https://discourse.julialang.org/u/jonniedie)\
**Post date:** [January 24, 2020, 2:52am UTC](https://discourse.julialang.org/t/anonymous-nested-struct/33723/2 "2020-01-24T02:52:38Z")

</div>

Maybe there is a reason to have something like this that I can’t immediately think of, but as far as readability goes I find your third example much more readable and aesthetically pleasing than the first.

---

<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:** [January 24, 2020, 3:01am UTC](https://discourse.julialang.org/t/anonymous-nested-struct/33723/3 "2020-01-24T03:01:23Z")

</div>

> [@Sijun](#):
>
> By “Anonymous nested struct” I mean defining a struct that has another struct with no name inside:

Named tuples are Julia’s anonymous structs:

```julia
struct ABC
   name::String
   data::NamedTuple{(:raw,:value),Tuple{Vector{Float64},Int}}
end

```

from which you can do:

```julia
julia> abc = ABC("foo",(raw=[3,4,5],value=17))
ABC("foo", (raw = [3.0, 4.0, 5.0], value = 17))

julia> abc.data.value
17

```

---

<div class="post-metadata">

**Author:** ![Sijun](https://avatars.discourse-cdn.com/v4/letter/s/b2d939/32.png) [@Sijun](https://discourse.julialang.org/u/Sijun)\
**Post date:** [January 24, 2020, 3:19am UTC](https://discourse.julialang.org/t/anonymous-nested-struct/33723/4 "2020-01-24T03:19:28Z")

</div>

Ah, yes, indeed NamedTuples are anonymous structs. But aesthetically, I still feel NamedTuple syntax looks a little bit cluttered than the first example. But I agree that it’s subjective and arguable.

Possible benefit of the first example is 1) fieldname and type are side by side 2) when deeply nested, it is more readable than NamedTuple:

```julia
struct ABC
    name::String
    data::struct
        raw::Vector{Float64}
        value::Int
        innerFields::struct
            val::Int
            name::String
            data::struct
                arr:Array{Float64, 3}
            end
        end
    end
end

```

Equivalent NamedTuple exression would be rather complex.

---

<div class="post-metadata">

**Author:** ![Sijun](https://avatars.discourse-cdn.com/v4/letter/s/b2d939/32.png) [@Sijun](https://discourse.julialang.org/u/Sijun)\
**Post date:** [January 24, 2020, 3:21am UTC](https://discourse.julialang.org/t/anonymous-nested-struct/33723/5 "2020-01-24T03:21:29Z")

</div>

It could be, but downside is we have to give it a name, sometimes could be annoying I suppose.

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [January 24, 2020, 3:52am UTC](https://discourse.julialang.org/t/anonymous-nested-struct/33723/6 "2020-01-24T03:52:48Z")

</div>

You can use `typeof`:

```julia
struct ABC
    name::String
    data::typeof((
        raw = [0.0],
        value = 0,
        innerFields = (val = 0, name = "", data = (arr = zeros(0, 0, 0),)),
    ))
end

```

---

<div class="post-metadata">

**Author:** ![Sijun](https://avatars.discourse-cdn.com/v4/letter/s/b2d939/32.png) [@Sijun](https://discourse.julialang.org/u/Sijun)\
**Post date:** [January 24, 2020, 3:59am UTC](https://discourse.julialang.org/t/anonymous-nested-struct/33723/7 "2020-01-24T03:59:25Z")

</div>

It could be one option…but maybe a little bothersome in that it requires to provide literals manually as part of the struct definition.

---

<div class="post-metadata">

**Author:** ![GunnarFarneback](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gunnarfarneback/32/1827_2.png) [@GunnarFarneback](https://discourse.julialang.org/u/GunnarFarneback)\
**Post date:** [January 24, 2020, 6:33am UTC](https://discourse.julialang.org/t/anonymous-nested-struct/33723/8 "2020-01-24T06:33:22Z")

</div>

> [@Sijun](#):
>
> Equivalent NamedTuple exression would be rather complex.

All of that is valid syntax, so a macro could rewrite the inner structs to named tuples.

---

<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:** [January 24, 2020, 1:32pm UTC](https://discourse.julialang.org/t/anonymous-nested-struct/33723/9 "2020-01-24T13:32:14Z")

</div>

> [@GunnarFarneback](#):
>
> All of that is valid syntax, so a macro could rewrite the inner structs to named tuples.

Yes, a macro might be useful here. For example:

```julia
macro NamedTuple(ex)
    Meta.isexpr(ex, :block) || error("@NamedTuple requires a begin-end block")
    decls = filter(e -> !(e isa LineNumberNode), ex.args)
    all(e -> Meta.isexpr(e, :(::)), decls) || error("@NamedTuple requires a block of name::type expressions")
    vars = [QuoteNode(e.args[1]) for e in decls]
    types = [e.args[2] for e in decls]
    return :(NamedTuple{($(vars...),), Tuple{$(types...)}})
end

```

allows you to do:

```julia
julia> @NamedTuple begin
           raw::Vector{Float64}
           value::Int
       end
NamedTuple{(:raw, :value),Tuple{Array{Float64,1},Int64}}

```

It might be reasonable to include something like this in Base, if someone wants to put together a PR.

See also [allow @foo{...} macro calls · Issue #34498 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/34498) regarding an alternative syntax `@NamedTuple{raw::Vector{Float64}, value::Int}` that might be a bit nicer. (Of course, a single macro could easily support both `{...}` and `begin ... end` syntaxes, just by using `Meta.isexpr(ex, :block) || Meta.isexpr(ex, :brace)` on the first line.)

_Update:_ [PR created](https://github.com/JuliaLang/julia/pull/34548)

---

<div class="post-metadata">

**Author:** ![Sijun](https://avatars.discourse-cdn.com/v4/letter/s/b2d939/32.png) [@Sijun](https://discourse.julialang.org/u/Sijun)\
**Post date:** [January 25, 2020, 2:44am UTC](https://discourse.julialang.org/t/anonymous-nested-struct/33723/10 "2020-01-25T02:44:20Z")

</div>

Glad to know that similar idea was already thought about!  
If would be great if it is capable of nesting like:

```julia
struct ABC
	name::String
	data::@NamedTuple begin
		raw::Vector{Float64}, 
		value::Int
		data::@NamedTuple begin
			arr::Vector{Float64};
		end
	end
end

```

if `@NamedTuple` could be made nested in `struct`, it should certainly be possible to nest `struct` for less typing for example:

```julia
@nested struct
    field::struct

    end 
end

```

Meta programming is a wonderful tool but also too mind-bending world to me.

---

<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:** [January 25, 2020, 4:16am UTC](https://discourse.julialang.org/t/anonymous-nested-struct/33723/11 "2020-01-25T04:16:42Z")

</div>

> [@Sijun](#):
>
> If would be great if it is capable of nesting like:

It is:

```julia
julia> @NamedTuple begin
                       raw::Vector{Float64}
                       value::Int
                       data::@NamedTuple begin
                               arr::Vector{Float64};
                       end
                   end
NamedTuple{(:raw, :value, :data),Tuple{Array{Float64,1},Int64,NamedTuple{(:arr,),Tuple{Array{Float64,1}}}}}

```

---

<div class="post-metadata">

**Author:** ![Sijun](https://avatars.discourse-cdn.com/v4/letter/s/b2d939/32.png) [@Sijun](https://discourse.julialang.org/u/Sijun)\
**Post date:** [January 26, 2020, 2:25pm UTC](https://discourse.julialang.org/t/anonymous-nested-struct/33723/12 "2020-01-26T14:25:08Z")

</div>

It works! why didn’t it work yesterday? I ran the code on a computer with Julia 1.1.1 installed. Now I run it on Julia 1.3 and confirm it works. I am staring at your code to understand it. 🙂 Its should go to Base.

---

<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:** [January 26, 2020, 5:53pm UTC](https://discourse.julialang.org/t/anonymous-nested-struct/33723/13 "2020-01-26T17:53:06Z")

</div>

> [@Sijun](#):
>
> It works! why didn’t it work yesterday?

The code you posted above had an extra comma on the `raw` line.
