# Basic struct usage questions

**URL:** <https://discourse.julialang.org/t/basic-struct-usage-questions/68932>\
**Category:** New to Julia\
**Tags:** type, parametric-types, struct\
**Created:** [September 29, 2021, 1:30pm UTC](https://discourse.julialang.org/t/basic-struct-usage-questions/68932 "2021-09-29T13:30:20Z")\
**Posts on this page:** 12\
**Page:** 2

<div class="post-metadata">

**Author:** ![Nathan\_Boyer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nathan_boyer/32/14825_2.png) [@Nathan\_Boyer](https://discourse.julialang.org/u/Nathan_Boyer)\
**Post date:** [September 29, 2021, 2:36pm UTC](https://discourse.julialang.org/t/basic-struct-usage-questions/68932/22 "2021-09-29T14:36:24Z")

</div>

> [@pdeffebach](#):
>
> If you define iteration for your type, (which is easy), then `std` , `var` , `sum` , etc. all intuitively make sense to the user, and don’t need to be overloaded or documented. Since its the same behavior as the docstring for `sum(::Any)` which exists in base.

Can you show me or point me to documentation on defining iteration on my type?

---

<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 29, 2021, 2:41pm UTC](https://discourse.julialang.org/t/basic-struct-usage-questions/68932/23 "2021-09-29T14:41:57Z")

</div>

Note, you don’t need to do this if you go with the StaticArrays.jl solution. StaticArrays.jl will do this for you.

A quick google search of “iteration define julia” gives the following [link](https://docs.julialang.org/en/v1/manual/interfaces/) to the docs.

---

<div class="post-metadata">

**Author:** ![Nathan\_Boyer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nathan_boyer/32/14825_2.png) [@Nathan\_Boyer](https://discourse.julialang.org/u/Nathan_Boyer)\
**Post date:** [September 29, 2021, 2:45pm UTC](https://discourse.julialang.org/t/basic-struct-usage-questions/68932/24 "2021-09-29T14:45:24Z")

</div>

> [@Tamas\_Papp](#):
>
> Generally, users should understand the API that your types conform to; if that is clear then they have no need to understand type internals.

I don’t have a good understanding of what API means yet, so I’m not following the distinction you are making.

---

<div class="post-metadata">

**Author:** ![gustaphe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gustaphe/32/18174_2.png) [@gustaphe](https://discourse.julialang.org/u/gustaphe)\
**Post date:** [September 29, 2021, 2:48pm UTC](https://discourse.julialang.org/t/basic-struct-usage-questions/68932/25 "2021-09-29T14:48:06Z")

</div>

It depends on the context, but normally defining

```julia
function f(x) end
function f(x::AbstractArray) end

```

does this job.

---

<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 29, 2021, 2:56pm UTC](https://discourse.julialang.org/t/basic-struct-usage-questions/68932/26 "2021-09-29T14:56:18Z")

</div>

The API is basically the way the user interacts with your objects. It’s all the things they can do with your object.

You can have a super complicated object

```julia
struct MyComplicatedObject{T}
    a::T
    b::Float64
    c:::T
    ...
    z::String
end

```

but then the only function you define for it is `onesinglefunction`

```julia
onesinglefunction(x::MyComplicatedObject) = x.a

```

Then the function `onesinglefunction` is the API and the user doesn’t ever need to know there are fields `a` through `z` in the struct.

---

<div class="post-metadata">

**Author:** ![Nathan\_Boyer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nathan_boyer/32/14825_2.png) [@Nathan\_Boyer](https://discourse.julialang.org/u/Nathan_Boyer)\
**Post date:** [September 29, 2021, 7:56pm UTC](https://discourse.julialang.org/t/basic-struct-usage-questions/68932/27 "2021-09-29T19:56:43Z")

</div>

> [@jling](#):
>
> these are abstract types, bad practices.

> [@Jeff\_Emanuel](#):
>
> I think you want parameteric types so that the struct members are not abstract.

I read [Parametric Composite Types](https://docs.julialang.org/en/v1/manual/types/#man-parametric-composite-types), but I’m still a bit confused on the best way forward with types.

```julia
struct CylindricalStress1
    r::Number
    θ::Number
    z::Number
end

struct CylindricalStress2{T} #where T <: Number
    r::T
    θ::T
    z::T
end

```

```julia
julia> σ1 = CylindricalStress1(1.1, 1.2, 1.3)
CylindricalStress1(1.1, 1.2, 1.3)

julia> σ2 = CylindricalStress2(1.1, 1.2, 1.3)
CylindricalStress2{Float64}(1.1, 1.2, 1.3)

julia> σ3 = CylindricalStress1(1, 2, 3.3)
CylindricalStress1(1, 2, 3.3)

julia> σ4 = CylindricalStress2(1, 2, 3.3)
ERROR: LoadError: MethodError: no method matching CylindricalStress2(::Int64, ::Int64, ::Float64)

```

It seems like `CylindricalStress1` is more flexible at the cost of speed. It might be possible for an `Int` to make it through my `lame` function, and it would be pretty _lame_ 😉 if the user received the `σ4` error because not all the entries converted to `Float64`. Should I stick with `CylindricalStress1` or force a conversion to `Float64` somewhere so I can use the faster `CylindricalStress2`? I wouldn’t want to convert Unitful.jl types to Float64 though.

Also, why do I get `ERROR: LoadError: syntax: invalid type signature` when I uncomment `where T <: Number`? What is the proper way to restrict the type of T? I don’t want to allow vectors.

Lastly, I notice that the types of the fields are the same in either case, so it is just the type of the container that is changing.

```julia
julia> typeof(σ1.r)
Float64

julia> typeof(σ2.r)
Float64

julia> typeof(σ3.r)
Int64

julia> typeof(σ4.r)
ERROR: LoadError: UndefVarError: σ4 not defined

```

---

<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 29, 2021, 8:20pm UTC](https://discourse.julialang.org/t/basic-struct-usage-questions/68932/28 "2021-09-29T20:20:07Z")

</div>

> [@Nathan\_Boyer](#):
>
> Should I stick with `CylindricalStress1` or force a conversion to `Float64` somewhere so I can use the faster `CylindricalStress2` ? I wouldn’t want to convert Unitful.jl types to Float64 though.

You should handle this in the constructor, but you need to use an [inner constructor](https://docs.julialang.org/en/v1/manual/constructors/#man-inner-constructor-methods) for it

```julia
julia> struct CS{T<:Number}
           r::T
           θ::T
           z::T

           CS(r, θ, z) = begin
               T = mapreduce(typeof, promote_type, (r, θ, z))
               new{T}(convert(T, r), convert(T, θ), convert(T, z))
           end
       end

julia> CS(1, 2.0, 5)
CS{Float64}(1.0, 2.0, 5.0)

julia> CS(1u"kg", 2.0, 5)
CS{Quantity{Float64, D, U} where {D, U}}(1.0 kg, 2.0, 5.0)

```

I’m actually not 100% on whether or not I’m doing this conversion right. Hopefully someone better informed can chime in

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [September 29, 2021, 10:27pm UTC](https://discourse.julialang.org/t/basic-struct-usage-questions/68932/29 "2021-09-29T22:27:11Z")

</div>

I think an outer constructor of:

```julia
CS(x,y,z) = CS(promote(x,y,z)...)

```

would be fine

---

<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 30, 2021, 12:45am UTC](https://discourse.julialang.org/t/basic-struct-usage-questions/68932/30 "2021-09-30T00:45:21Z")

</div>

No, this leads to a stackoverflow i think. It needs to be in the inner constructor. At least that’s what I had when making that MWE above.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [September 30, 2021, 1:02am UTC](https://discourse.julialang.org/t/basic-struct-usage-questions/68932/31 "2021-09-30T01:02:05Z")

</div>

```julia
julia> struct CS{T<:Number}
                  r::T
                  θ::T
                  z::T
       end

julia> CS(1,2,3)
CS{Int64}(1, 2, 3)

julia> CS(x,y,z) = CS(promote(x,y,z)...)
CS

julia> CS(1,2,3)
CS{Int64}(1, 2, 3)

julia> CS(1,2,3.0)
CS{Float64}(1.0, 2.0, 3.0)

```

looks fine

---

<div class="post-metadata">

**Author:** ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)\
**Post date:** [September 30, 2021, 1:13pm UTC](https://discourse.julialang.org/t/basic-struct-usage-questions/68932/32 "2021-09-30T13:13:23Z")

</div>

Ah, my bad, I just saw the first type definition

```julia
"""
    abstract type Unitlike end
Represents units or dimensions. Dimensions are unit-like in the sense that they are
not numbers but you can multiply or divide them and exponentiate by rationals.
"""
abstract type Unitlike end

```

and wrongly decided those are the unitful values.

But I did get burnt with subtypes of `Number` which seemed appropriate for the problem but turned out problematic when I tried AD, and thus just accepted that unitfuls may be not numbers without even checking.

> [@Nathan\_Boyer](#):
>
> Should I stick with `CylindricalStress1` or force a conversion to `Float64` somewhere so I can use the faster `CylindricalStress2` ? I wouldn’t want to convert Unitful.jl types to Float64 though.

To add to @pdeffebach’s and @jling’s suggestions:

```julia
struct CS{Tx<:Number, Ta<:Number}
    r::Tx
    θ::Ta
    z::Tx

    function CS(rr, θ, zz)
        r, z = promote(float(rr), float(zz))
        Ta = float(typeof(θ))
        Tx = typeof(r)
        return new{Tx, Ta}(r, θ, z)
    end
end

```

That handles converting to floating point types and the fact that unitful r and \theta have different units.

---

<div class="post-metadata">

**Author:** ![Nathan\_Boyer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nathan_boyer/32/14825_2.png) [@Nathan\_Boyer](https://discourse.julialang.org/u/Nathan_Boyer)\
**Post date:** [September 30, 2021, 9:03pm UTC](https://discourse.julialang.org/t/basic-struct-usage-questions/68932/33 "2021-09-30T21:03:54Z")

</div>

**Solution to Question #1**

> [@lmiq](#):
>
> Maybe `FieldVector` from `StaticArrays`  
> …  
> (although, as pointed above, some of the operations may not make sense - the `norm` being one of them. Others, like the `sum`, maybe?)
> 
> You could start from that and overload some functions that you need with specific implementations when needed.

`norm` and `sum` do work natively as I wanted with `StaticArrays`.

_Alternative:_

> [@pdeffebach](#):
>
> I think the key thing is whether or not it is iterable. If you [define iteration for your type](https://docs.julialang.org/en/v1/manual/interfaces/index.html), (which is easy), then `std` , `var` , `sum` , etc. all intuitively make sense to the user, and don’t need to be overloaded or documented. Since its the same behavior as the docstring for `sum(::Any)` which exists in base.

**Solution to Question #2**

> [@rdeits](#):
>
> `AbstractVector` or `AbstractArray` (depending on whether you actually want precisely a 1-dimensional array or you just want any array of any number of dimensions) is usually a good choice. Restricting your number-like scalar types to a subtype of `Number` is probably a good compromise between flexibility and providing an explicit signal to your users about what kind of input is expected.
> 
> Also, I think you’ve been misinformed about `Number` and `Unitful`:  
> …  
> A `Unitful.Quantity` is a subtype of `Number`, so you can use `::Number` for type annotations even if you want to accept unitful quantities.

> [@Jeff\_Emanuel](#):
>
> I think you want parameteric types so that the struct members are not abstract.

Thus, I will switch to the following type definitions provided by @jling and @lmiq.

```julia
struct CylindricalStress{T<:Number} <: FieldVector{3,T}
    r::T # Radial Stress
    θ::T # Tangential (Hoop) Stress
    z::T # Longitudinal Stress
end
CylindricalStress(x, y, z) = CylindricalStress(promote(x, y, z)...) # Outer constructor

function lame(r::AbstractVector, pᵢ::Number, pₒ::Number=0)
    # function definition
end

```

```julia
julia> σ = lame([5, 10, 15], 100)
3-element Vector{CylindricalStress{Float64}}:
 [-100.0, 125.0, 12.5]
 [-15.625, 40.625, 12.5]
 [0.0, 25.0, 12.5]

julia> norm.(σ)
3-element Vector{Float64}:
 160.56540723331412
  45.285552331842
  27.95084971874737

julia> mean(σ)
3-element CylindricalStress{Float64} with indices SOneTo(3):
 -38.541666666666664
  63.541666666666664
  12.5

```

**Solution to Question #3**

> [@pdeffebach](#):
>
> The API is basically the way the user interacts with your objects. It’s all the things they can do with your object.
> 
> You can have a super complicated object
> 
> ```julia
> struct MyComplicatedObject{T}
> a::T
> b::Float64
> c:::T
> ...
> z::String
> end
> 
> ```
> 
> but then the only function you define for it is `onesinglefunction`
> 
> ```julia
> onesinglefunction(x::MyComplicatedObject) = x.a
> 
> ```
> 
> Then the function `onesinglefunction` is the API and the user doesn’t ever need to know there are fields `a` through `z` in the struct.

Although in my case, I don’t have any extra fields that the user wouldn’t care about.

[Previous page](https://discourse.julialang.org/t/basic-struct-usage-questions/68932.md?page=1)
