# How to use a numerical type parameters in declaration

**URL:** <https://discourse.julialang.org/t/how-to-use-a-numerical-type-parameters-in-declaration/58535>\
**Category:** General Usage\
**Tags:** parametric-types\
**Created:** [April 3, 2021, 11:22pm UTC](https://discourse.julialang.org/t/how-to-use-a-numerical-type-parameters-in-declaration/58535 "2021-04-03T23:22:36Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![jsjie](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jsjie/32/22477_2.png) [@jsjie](https://discourse.julialang.org/u/jsjie)\
**Post date:** [April 3, 2021, 11:22pm UTC](https://discourse.julialang.org/t/how-to-use-a-numerical-type-parameters-in-declaration/58535/1 "2021-04-03T23:22:36Z")

</div>

I’m trying to do something about physics, and I’ve written a struct like

```julia
struct System
    charge_density
end

```

now there is something called “spin” that may, but not must be considered in physics, and the data structure will be different. It looks something like

```julia
struct SystemNoSpin
    charge_density::Array{Float64, 3}
end

struct SystemWithSpin
    charge_density::Array{Float64, 4}
end

```

conventionally, we will set a variable called “SPIN” = 1 when not considering it, and 2 when considering. So I try to use parametric types. I found this is a practical way:

```julia
struct System{SPIN}
    charge_density::Array{Float64, SPIN+2}
end

```

but this is not:

```julia
charge_type = Dict{Int, Type}([(1, Array{Float64, 3}), (2, Array{Float64, 4})])
struct System{SPIN}
    charge_density::charge_type[SPIN]
end

```

it will raise “KeyError:: key SPIN not found”

However, I feel that the second way, if available, seems to be more readable. Any way to do it?

* * *

Maybe I should make it more clear what I want. In physics, there are many properties, and they may be categorized into many kinds. For example, all space-related properties are Array{T, 3} without spin and Array{T, 4} with spin, while all band-related properties are Array{T, 2} without spin and Array{T, 3} with spin. T maybe either Float64 or ComplexF64. That’s why I think the second way mentioned above is more readable. In that way I can define some type alias, some dictionaries, then write

```julia
struct System{SPIN}
    property1::space_related[SPIN]{Float64}
    property2::space_related[SPIN]{ComplexF64}
    property3::band_related[SPIN]{Float64}
end

```

On the contrary, in the first way I mentioned above, it can only be written as

```julia
struct System{SPIN}
    property1::Array{Float64, 2 + SPIN}
    property2::Array{ComplexF64, 2 + SPIN}
    property3::Array{Float64, 1 + SPIN}
end

```

And now I’ve turned to a third solution:

```julia
struct SpaceRelatedProperties{SPIN}
    property1::Array{Float64, 2 + SPIN}
    property2::Array{ComplexF64, 2 + SPIN}
end
struct BandRelatedProperties{SPIN}
    property3::Array{Float64, 1 + SPIN}
end
struct System{SPIN}
    s_p::SpaceRelatedProperties{SPIN}
    b_p::BandRelatedProperties{SPIN}
end

```

Any better ways?

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [April 3, 2021, 11:49pm UTC](https://discourse.julialang.org/t/how-to-use-a-numerical-type-parameters-in-declaration/58535/2 "2021-04-03T23:49:26Z")

</div>

I think your type declaration could be:

```julia
julia> struct System{SPIN,N}
           charge_density::Array{Float64}
       end

```

and then one or other option lies in the constructors:

```julia
julia> function System(spin,n) # not sure what is the size of the array you want
         if spin == 1
           return System{spin,n}(zeros(Float64,n,n,n))
         elseif spin == 2
           return System{spin,n}(zeros(Float64,n,n,n,n))
         else
           error(" spin must be 1 or 2 ")
         end
       end
System

julia> System(1,4) 
System{1,4}([0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0]

[0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0]

[0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0]

[0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0])

julia> System(2,3)
System{2,3}([0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0]

[0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0]

[0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0]

[0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0]

[0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0]

[0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0]

[0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0]

[0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0]

[0.0 0.0 0.0; 0.0 0.0 0.0; 0.0 0.0 0.0])

```

---

<div class="post-metadata">

**Author:** ![jsjie](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jsjie/32/22477_2.png) [@jsjie](https://discourse.julialang.org/u/jsjie)\
**Post date:** [April 4, 2021, 12:20am UTC](https://discourse.julialang.org/t/how-to-use-a-numerical-type-parameters-in-declaration/58535/3 "2021-04-04T00:20:11Z")

</div>

I think your point is, not specifying the concrete dimensions in type declaration, but during construction. It is a nice suggestion, but I think it differs not much from the first way I’ve discussed.

---

<div class="post-metadata">

**Author:** ![mcabbott](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mcabbott/32/6603_2.png) [@mcabbott](https://discourse.julialang.org/u/mcabbott)\
**Post date:** [April 4, 2021, 12:41am UTC](https://discourse.julialang.org/t/how-to-use-a-numerical-type-parameters-in-declaration/58535/4 "2021-04-04T00:41:03Z")

</div>

> [@jsjie](#):
>
> ```julia
> struct System{SPIN}
> charge_density::Array{Float64, SPIN+2}
> end
> 
> ```

I don’t think you can do this, don’t you get this error?

```julia
julia> struct System{SPIN}
           charge_density::Array{Float64, SPIN+2}
       end
ERROR: MethodError: no method matching +(::TypeVar, ::Int64)

julia> methods(System)
# 0 methods for type constructor:

```

The normal way, as @lmiq says, is to make the constructor enforce it. If you do this as an inner constructor, then there will be no method to construct a mismatched object:

```julia
julia> struct System2{SPIN, N}
           charge_density::Array{Float64, N}
           System2(x::Array) = new{ndims(x)-2, ndims(x)}(x)
       end

julia> System2(ones(2,2)) isa System2{0}
true

```

You can also use [GitHub - vtjnash/ComputedFieldTypes.jl: Build types in Julia where some fields have computed types](https://github.com/vtjnash/ComputedFieldTypes.jl) to write and handle the extra type parameters for you:

```julia
julia> using ComputedFieldTypes

julia> @macroexpand @computed struct SystemC{SPIN}
                      charge_density::Array{Float64, SPIN+2}
                    end
quote
    struct SystemC{SPIN, var"##272"}
        #= REPL[8]:2 =#
        charge_density::Array{Float64, var"##272"}
        function (::Base.Type{SystemC{SPIN}})(charge_density) where SPIN
            return new{SPIN, SPIN + 2}(charge_density)
        end
    end
    function ComputedFieldTypes.fulltype(::Base.Type{SystemC{SPIN}}) where SPIN
        return SystemC{SPIN, SPIN + 2}
    end
end

```

---

<div class="post-metadata">

**Author:** ![jsjie](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jsjie/32/22477_2.png) [@jsjie](https://discourse.julialang.org/u/jsjie)\
**Post date:** [April 4, 2021, 12:50am UTC](https://discourse.julialang.org/t/how-to-use-a-numerical-type-parameters-in-declaration/58535/5 "2021-04-04T00:50:53Z")

</div>

when I test the code on my machine I only use a simplified version without +2 and 😰  
so the problem is that it is a typevar, not the Int passed in. I will try your ways.

---

<div class="post-metadata">

**Author:** ![jsjie](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jsjie/32/22477_2.png) [@jsjie](https://discourse.julialang.org/u/jsjie)\
**Post date:** [April 4, 2021, 1:16am UTC](https://discourse.julialang.org/t/how-to-use-a-numerical-type-parameters-in-declaration/58535/6 "2021-04-04T01:16:43Z")

</div>

Another question. I can add an additional dimension to non-spin case, in which the size is always 1, so that the dimension in both cases is the same. Will this additional dimension introduce much overhead? It seems much easier to complement.
