# Set array dimensions in composite type

**URL:** <https://discourse.julialang.org/t/set-array-dimensions-in-composite-type/57123>\
**Category:** General Usage\
**Created:** [March 14, 2021, 10:45am UTC](https://discourse.julialang.org/t/set-array-dimensions-in-composite-type/57123 "2021-03-14T10:45:58Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![weymouth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/weymouth/32/15839_2.png) [@weymouth](https://discourse.julialang.org/u/weymouth)\
**Post date:** [March 14, 2021, 10:45am UTC](https://discourse.julialang.org/t/set-array-dimensions-in-composite-type/57123/1 "2021-03-14T10:45:58Z")

</div>

How can you define arrays of increasing dimension in a composite type when they have a simple form such as the following?

```julia
struct compound{N} # N is the number of spatial dimensions of the field
    scalar_field :: Array{Float64,N}
    vector_field :: Array{Float64,N+1}
    tensor_field :: Array{Float64,N+2}
end

```

But this throws the error

> **MethodError: no method matching +(::TypeVar, ::Int64)**

I guess I could make an Array of Arrays, but I would rather keep them flat like this.

---

<div class="post-metadata">

**Author:** ![tomerarnon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomerarnon/32/3170_2.png) [@tomerarnon](https://discourse.julialang.org/u/tomerarnon)\
**Post date:** [March 14, 2021, 11:16am UTC](https://discourse.julialang.org/t/set-array-dimensions-in-composite-type/57123/2 "2021-03-14T11:16:16Z")

</div>

I think you have to settle for three type parameters and an assertion:

```julia
struct Compound{N, M, P}
    scalar_field::Array{Float64, N}
    vector_field::Array{Float64, M}
    tensor_field::Array{Float64, P}

    function Compound(s, v, t)
        # alternatively throw a more appropriate error type like
        # a DimensionMismatch or MethodError
        @assert ndims(s) == ndims(v)-1 == ndims(t)-2 "error message about dimension" 
        N = ndims(s)
        new{N, N+1, N+2}(s, v, t)
    end
end

```

---

<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:** [March 14, 2021, 11:17am UTC](https://discourse.julialang.org/t/set-array-dimensions-in-composite-type/57123/3 "2021-03-14T11:17:47Z")

</div>

I don’t know of any better way than parameterizing `Compound` with three independent parameters (e.g. `N`, `N1`, `N2`) and enforce the relation between them in an inner constructor.

Something along the lines of:

```julia
julia> struct Compound{N, N1, N2}
           scalar_field :: Array{Float64,N} # N is the number of spatial dimensions of the field
           vector_field :: Array{Float64,N1} # N1 should be N+1
           tensor_field :: Array{Float64,N2} # N2 should be N+2
       
           function Compound(N)
               new{N, N+1, N+2}()
           end
       end

julia> Compound(5)
Compound{5,6,7}(#undef, #undef, #undef)

```

---

<div class="post-metadata">

**Author:** ![weymouth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/weymouth/32/15839_2.png) [@weymouth](https://discourse.julialang.org/u/weymouth)\
**Post date:** [March 14, 2021, 11:22am UTC](https://discourse.julialang.org/t/set-array-dimensions-in-composite-type/57123/4 "2021-03-14T11:22:58Z")

</div>

Drats! That’s what I’m doing now and it is soooo ugly.

---

<div class="post-metadata">

**Author:** ![LaurentPlagne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laurentplagne/32/10103_2.png) [@LaurentPlagne](https://discourse.julialang.org/u/LaurentPlagne)\
**Post date:** [March 14, 2021, 11:24am UTC](https://discourse.julialang.org/t/set-array-dimensions-in-composite-type/57123/5 "2021-03-14T11:24:28Z")

</div>

```julia
struct Compound{N}
    scalar_field :: Array{Float64,N}
    vector_field :: Array{SVector{1,Float},N}
    tensor_field :: Array{SVector{2,Float},N} 
end

```

Maybe ?

---

<div class="post-metadata">

**Author:** ![weymouth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/weymouth/32/15839_2.png) [@weymouth](https://discourse.julialang.org/u/weymouth)\
**Post date:** [March 14, 2021, 11:26am UTC](https://discourse.julialang.org/t/set-array-dimensions-in-composite-type/57123/6 "2021-03-14T11:26:24Z")

</div>

Yeah, the is the _array of arrays_ that I was considering above. Is there a performance hit for nesting arrays like this?

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [March 14, 2021, 11:29am UTC](https://discourse.julialang.org/t/set-array-dimensions-in-composite-type/57123/7 "2021-03-14T11:29:02Z")

</div>

You could try with meta programming

```julia

abstract type AbstractCompound{N} end

for N = 1:4
    name = Symbol("Compound$N")
    @eval begin
        struct $name <: AbstractCompound{$(N)} # N is the number of spatial dimensions of the field
            scalar_field :: Array{Float64,$(N)}
            vector_field :: Array{Float64,$(N+1)}
            tensor_field :: Array{Float64,$(N+2)}
        end
    end
end

julia> c = Compound1(zeros(1),zeros(1,1),zeros(1,1,1))
Compound1([0.0], [0.0], [0.0])

julia> c.tensor_field
1×1×1 Array{Float64, 3}:
[:, :, 1] =
 0.0

```

---

<div class="post-metadata">

**Author:** ![LaurentPlagne](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/laurentplagne/32/10103_2.png) [@LaurentPlagne](https://discourse.julialang.org/u/LaurentPlagne)\
**Post date:** [March 14, 2021, 11:31am UTC](https://discourse.julialang.org/t/set-array-dimensions-in-composite-type/57123/8 "2021-03-14T11:31:52Z")

</div>

Oops ! Too fast reading (although not fast enough to provide the first solution 😉 )  
I think that you can reshape your arrays as flat arrays.  
If you want to minimize the performance risks maybe you may adopt a SoA strategy (but the client code is likely to be “uglier”)

I am thinking about the best strategy and I confess that at this point nothing’s really convince me…

---

<div class="post-metadata">

**Author:** ![weymouth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/weymouth/32/15839_2.png) [@weymouth](https://discourse.julialang.org/u/weymouth)\
**Post date:** [March 14, 2021, 11:44am UTC](https://discourse.julialang.org/t/set-array-dimensions-in-composite-type/57123/9 "2021-03-14T11:44:20Z")

</div>

Neat! This would be much nicer when writing thing like `foo(a::AbstractCompound{N}) where N`.

Would it be possible to overload the internal constructor? I often have code like `b = Compound(a.scalar_field)` and now it looks like I would need to check if I needed `Compound2`, `Compound3`,…

---

<div class="post-metadata">

**Author:** ![weymouth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/weymouth/32/15839_2.png) [@weymouth](https://discourse.julialang.org/u/weymouth)\
**Post date:** [March 14, 2021, 11:45am UTC](https://discourse.julialang.org/t/set-array-dimensions-in-composite-type/57123/10 "2021-03-14T11:45:12Z")

</div>

Thanks. That’s my current approach.

---

<div class="post-metadata">

**Author:** ![baggepinnen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/baggepinnen/32/693_2.png) [@baggepinnen](https://discourse.julialang.org/u/baggepinnen)\
**Post date:** [March 14, 2021, 12:04pm UTC](https://discourse.julialang.org/t/set-array-dimensions-in-composite-type/57123/11 "2021-03-14T12:04:12Z")

</div>

> [@weymouth](#):
>
> Would it be possible to overload the internal constructor? I often have code like `b = Compound(a.scalar_field)` and now it looks like I would need to check if I needed `Compound2` , `Compound3` ,…

You can solve this problem the same way, with meta programming. The only thing to keep in mind is to interpolate the `N` variable into the evaluated expression with `$(N)`.

---

<div class="post-metadata">

**Author:** ![weymouth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/weymouth/32/15839_2.png) [@weymouth](https://discourse.julialang.org/u/weymouth)\
**Post date:** [March 14, 2021, 12:22pm UTC](https://discourse.julialang.org/t/set-array-dimensions-in-composite-type/57123/12 "2021-03-14T12:22:04Z")

</div>

This seems to work well!

```julia
abstract type AbstractCompound{N} end
for N = 1:4
    name = Symbol("Compound$N")
    @eval begin
        struct $name <: AbstractCompound{$(N)} # N is the number of spatial dimensions of the field
            scalar_field :: Array{Float64,$(N)}
            vector_field :: Array{Float64,$(N+1)}
            tensor_field :: Array{Float64,$(N+2)}
        end
        Compound(s::AbstractArray{Float64,$(N)},a...) = $name(s,a...)
    end
end
Compound(N) = Compound(rand(N...),zeros(N...,length(N)),ones(N...,length(N),length(N)))

julia> Compound((2,2)).vector_field
2×2×2 Array{Float64,3}:
[:, :, 1] =
 0.0 0.0
 0.0 0.0

[:, :, 2] =
 0.0 0.0
 0.0 0.0

```

---

<div class="post-metadata">

**Author:** ![tomerarnon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomerarnon/32/3170_2.png) [@tomerarnon](https://discourse.julialang.org/u/tomerarnon)\
**Post date:** [March 14, 2021, 4:14pm UTC](https://discourse.julialang.org/t/set-array-dimensions-in-composite-type/57123/13 "2021-03-14T16:14:11Z")

</div>

I’m glad you found a solution that works for you! I do have some more thoughts reading through all the replies though.

> [@weymouth](#):
>
> Drats! That’s what I’m doing now and it is soooo ugly.

What aspect is ugly? The definition itself, the REPL printout `Compound{5, 6, 7}`, or something else? If it is the definition, then of course you’re out of luck with this method. If it’s the printout or having to refer to a type with 3 parameters elsewhere in the code, then there are simple enough remedies.

> [@weymouth](#):
>
> Neat! This would be much nicer when writing thing like `foo(a::AbstractCompound{N}) where N` .

If the N is necessary for the method, you would still need to write it this way I think. If not, you can omit it either way. Note also that you can write parameterized types with only some of the parameters defined. The parameters are interpreted in order.

```julia
julia> AbstractCompound == AbstractCompound{N} where N
true

julia> Compound{1}
Compound{1,M,P} where P where M

julia> Array{Int} # same idea as this
Array{Int64,N} where N

```

If for whatever reason you need the type to be totally concrete for some usage but don’t want to refer to it with all 3 parameters, you could define something like `compoundtype(n) = Compound{n, n+1, n+2}` as sugar for referring to the appropriate type. You could also define aliases like `const Compound1 = Compound{1,2,3}` which is similar to what you’re doing now.

Finally, the constructor you defined for `Compound(N)` would work (as written) just as well for a type with 3 parameters under the hood.

All of this is not to say that metaprogramming and having multiple types for Compound1, Compound2, etc. is not also a perfectly good way to go!

---

<div class="post-metadata">

**Author:** ![weymouth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/weymouth/32/15839_2.png) [@weymouth](https://discourse.julialang.org/u/weymouth)\
**Post date:** [March 14, 2021, 4:20pm UTC](https://discourse.julialang.org/t/set-array-dimensions-in-composite-type/57123/14 "2021-03-14T16:20:23Z")

</div>

Nice! I didn’t realize you could drop some of the parameters. That does clean up the usage a good deal.

I still prefer strictly defining `n,n+1,n+2` if possible since there really is only one parameter for the type, not three.

---

<div class="post-metadata">

**Author:** ![weymouth](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/weymouth/32/15839_2.png) [@weymouth](https://discourse.julialang.org/u/weymouth)\
**Post date:** [March 17, 2021, 7:52pm UTC](https://discourse.julialang.org/t/set-array-dimensions-in-composite-type/57123/15 "2021-03-17T19:52:14Z")

</div>

Point of fact - I ended up doing this since it was the closest to what I had already, so why reinvent the wheel?
