# 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:** 20\
**Page:** 1

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

</div>

I have defined a type called `CylindricalStress` for bundling the results of [Lamé’s Equations](https://www.mydatabook.org/solid-mechanics/stress-for-thick-walled-cylinders-and-spheres-using-lames-equations/) which I understand is good practice:

```julia
struct CylindricalStress
    r::Number # Radial Stress
    θ::Number # Tangential (Hoop) Stress
    z::Number # Longitudinal Stress
end

"""
    lame(r, pᵢ, pₒ=0)

Compute theoretical stress distribution from Lamé's thick wall cylinder equations.

# Arguments
- `r `: vector of points to compute stress over; must span from inside boundary to outside boundary
- `pᵢ`: pressure on inside boundary
- `pₒ`: pressure on outside boundary (pₒ=0 if argument is omitted)
"""
function lame(r::AbstractVector, pᵢ, pₒ = 0)
    (rᵢ, rₒ) = extrema(r)

    term1 = (rᵢ^2 * pᵢ - rₒ^2 * pₒ) / (rₒ^2 - rᵢ^2)
    term2 = rᵢ^2 * rₒ^2 * (pᵢ - pₒ) / (rₒ^2 - rᵢ^2) ./ r.^2

    σr = term1 .- term2
    σθ = term1 .+ term2
    σz = fill(term1, length(r))
    σ = CylindricalStress.(σr, σθ, σz)
    return σ
end

```

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

```

**1. How can I define my type as a subtype of something else so I don’t have to extend every function manually?**  
I just want this to act like any three-component vector for `sum(σ)`, `mean(σ)`, `10.*σ`, `norm.(σ)`, etc.

**2. What types should I enforce in the `struct` and in the `function`?**  
I have heard you need `AbstractVector` in order to accept a slice, and that you can’t restrict to `Number` if you want to accept [Uniful.jl](https://github.com/PainterQubits/Unitful.jl) types. I would like to give the user some indication of what to input, especially scalar vs vector. (I debugged some errors already related to this.) How can I provide wide compatibility, but also helpful documentation and error checking on input/output types?

**3. How can I keep my type as a “private implementation detail”?**  
I have heard the stance on this forum that custom types should not be publicly available. Why is that and how would that be implemented in this case?

---

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

</div>

> [@Nathan\_Boyer](#):
>
> ```julia
> r::Number # Radial Stress
> θ::Number # Tangential (Hoop) Stress
> z::Number # Longitudinal Stress
> 
> ```

these are abstract types, bad practices.

There’s no good solution to 1, as far as I can tell, this isn’t really a vector, the tree components are different components, similar to `Point(x,y)` is not (logically) similar to a vector with 2 elements.

---

<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:** [September 29, 2021, 1:45pm UTC](https://discourse.julialang.org/t/basic-struct-usage-questions/68932/3 "2021-09-29T13:45:07Z")

</div>

> [@Nathan\_Boyer](#):
>
> 1. How can I define my type as a subtype of something else so I don’t have to extend every function manually?

Maybe `FieldVEctor` from `StaticArrays`:

```julia
julia> using StaticArrays

julia> struct CylindricalStress{T} <: FieldVector{3,T}
           r::T # Radial Stress
           θ::T # Tangential (Hoop) Stress
           z::T # Longitudinal Stress
       end

julia> x = rand(CylindricalStress{Float64})
3-element CylindricalStress{Float64} with indices SOneTo(3):
 0.4695879908230596
 0.5473285905891696
 0.1754218840752042

julia> using LinearAlgebra

julia> norm(x)
0.7421955972747745

julia> v = rand(CylindricalStress{Float64},4)
4-element Vector{CylindricalStress{Float64}}:
 [0.8180545584117769, 0.10041135767552167, 0.38783069260937464]
 [0.6358575553230066, 0.8592006273725905, 0.7945119110861931]
 [0.8944549081297775, 0.12048601852665253, 0.8480448102782157]
 [0.4306380623978796, 0.17528782969751577, 0.821600492706112]

julia> sum(v)
3-element CylindricalStress{Float64} with indices SOneTo(3):
 2.7790050842624403
 1.2553858332722805
 2.8519879066798954

```

(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.

---

<div class="post-metadata">

**Author:** ![oheil](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oheil/32/220745_2.png) [@oheil](https://discourse.julialang.org/u/oheil)\
**Post date:** [September 29, 2021, 1:46pm UTC](https://discourse.julialang.org/t/basic-struct-usage-questions/68932/4 "2021-09-29T13:46:12Z")

</div>

> [@Nathan\_Boyer](#):
>
> **1. How can I define my type as a subtype of something else so I don’t have to extend every function manually?**  
> I just want this to act like any three-component vector for `sum(σ)` , `mean(σ)` , `10.*σ` , `norm.(σ)` , etc.

I think this is relevant:  
[https://docs.julialang.org/en/v1/manual/interfaces/index.html#man-interface-array](https://docs.julialang.org/en/v1/manual/interfaces/index.html#man-interface-array)

in general:  
[https://docs.julialang.org/en/v1/manual/interfaces/index.html](https://docs.julialang.org/en/v1/manual/interfaces/index.html)

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [September 29, 2021, 1:50pm UTC](https://discourse.julialang.org/t/basic-struct-usage-questions/68932/5 "2021-09-29T13:50:32Z")

</div>

> [@Nathan\_Boyer](#):
>
> **3. How can I keep my type as a “private implementation detail”?**  
> I have heard the stance on this forum that custom types should not be publicly available. Why is that and how would that be implemented in this case?

I’m not sure what you’re referring to here. Can you give an example?

There are no “private” types in Julia, and there’s no way to hide a struct definition. I’d say don’t worry about trying to hide things unless you have some really compelling special reason.

---

<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:** [September 29, 2021, 1:52pm UTC](https://discourse.julialang.org/t/basic-struct-usage-questions/68932/6 "2021-09-29T13:52:14Z")

</div>

> [@Nathan\_Boyer](#):
>
> Why is that and how would that be implemented in this case?

I think this is not a particular concern in general. Just not `export` the types, if the user doesn’t have to access them directly.

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [September 29, 2021, 1:55pm UTC](https://discourse.julialang.org/t/basic-struct-usage-questions/68932/7 "2021-09-29T13:55:13Z")

</div>

> [@Nathan\_Boyer](#):
>
> **2. What types should I enforce in the `struct` and in the `function` ?**  
> I have heard you need `AbstractVector` in order to accept a slice, and that you can’t restrict to `Number` if you want to accept [Uniful.jl](https://github.com/PainterQubits/Unitful.jl) types.

`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`:

```julia
julia> supertypes(typeof(1u"m"))
(Quantity{Int64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, Unitful.AbstractQuantity{Int64, 𝐋, Unitful.FreeUnits{(m,), 𝐋, nothing}}, Number, Any)

julia> 1u"m" isa Number
true

```

A `Unitful.Quantity` is a subtype of `Number`, so you can use `::Number` for type annotations even if you want to accept unitful quantities.

---

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

</div>

> [@rdeits](#):
>
> I’m not sure what you’re referring to here. Can you give an example?

Reference for question #3:

> [@Documenting elements of a struct](https://discourse.julialang.org/t/documenting-elements-of-a-struct/64769/33):
>
> I agree that struct fields should be considered implementation details unless specified otherwise, but I find that documenting things that are not part of the API is also useful. I docstring a lot of internal functions, type specs, and fields, so that when I come back to the code 2 years after I wrote it I can navigate it better. Also, this helps potential contributors.

---

<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, 1:59pm UTC](https://discourse.julialang.org/t/basic-struct-usage-questions/68932/10 "2021-09-29T13:59:03Z")

</div>

> [@rdeits](#):
>
> Also, I think you’ve been misinformed about `Number` and `Unitful` :

Reference for question #2:

> [@Are generic types worth the complexity?](https://discourse.julialang.org/t/are-generic-types-worth-the-complexity/67658/3):
>
> It’s worth it to at least annotate argument types as AbstractVector or alike. Because it won’t be long before someone would like to pass an array view to a function that only accepts Vectors. I would not recommend constraining the element type of collection at all because e.g. units from [Unitful.jl](https://github.com/PainterQubits/Unitful.jl) do not subtype Number but may be used as number-like values in many circumstances. I agree that it’s a bit disturbing, but couldn’t find a better solution man_shrugging

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [September 29, 2021, 2:07pm UTC](https://discourse.julialang.org/t/basic-struct-usage-questions/68932/11 "2021-09-29T14:07:10Z")

</div>

Fields being private unless indicated otherwise is just a convention, not something enforced by the language.

Cf the custom of not entering someone else’s home without being invited in, even if the door is unlocked.

---

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

</div>

Perhaps you can help us understand the implementation more. To calculate the `norm` of your `CylidricalStress`, is it just the euclidian norm of the elements?

Or are there other calculations involved, given one is the radial stress, one is the longitudinal stress?

---

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

</div>

Sorry, I **don’t** mean “How do I enforce privacy?”.  
I am wondering how you can get away with not explaining your types to the user? Define every possible function they could want to use it with in the package, and make sure those functions return only `Base` types?

---

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

</div>

I think the key thing is whether or not it is iterable. 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.

---

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

</div>

> [@pdeffebach](#):
>
> To calculate the `norm` of your `CylidricalStress` , is it just the euclidian norm of the elements?

Yes, the standard Euclidian norm equals the [von Mises equivalent stress](https://en.wikipedia.org/wiki/Von_Mises_yield_criterion) since these are principal stresses. `+`, `-`, `*`, `mean`, etc. will be used mostly for comparisons between datasets. I am going to be comparing the theoretical value above to FEA data. All those functions should act component-wise like a vector which is why I don’t want to bother defining all my own methods. However, I like the convenience of naming the components in my own `struct`.

---

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

</div>

> [@Nathan\_Boyer](#):
>
> Reference for question #2:

Yep, that’s misinformation.

There is a point to not needlessly restricting types, but `Number` is a fairly high level, not much of a restriction.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [September 29, 2021, 2:22pm UTC](https://discourse.julialang.org/t/basic-struct-usage-questions/68932/17 "2021-09-29T14:22:43Z")

</div>

I am not sure what “explaining your types” means in this context.

Generally, users should understand the API that your types conform to; if that is clear then they have no need to understand type internals. The API can be a polished interface like iteration, or something that you just define for this package.

---

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

</div>

> [@Nathan\_Boyer](#):
>
> All those functions should act component-wise like a vector which is why I don’t want to bother defining all my own methods.

Then `FieldVector` from `StaticArrays ` is probably the easiest path.

---

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

</div>

I 2nd this.

You _could_ implement the vector interface yourself, but if StaticArrays.jl does it for you, use that.

You can still overload other, more specialized, functions for your type. And document those. Seems pretty convenient.

---

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

</div>

> [@gustaphe](#):
>
> There is a point to not needlessly restricting types, but `Number` is a fairly high level, not much of a restriction.

Is using the type annotations `::Number` and `::AbstractArray` the best way to enforce scalars vs. collections respectively then?

---

<div class="post-metadata">

**Author:** ![Jeff\_Emanuel](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff_emanuel/32/15440_2.png) [@Jeff\_Emanuel](https://discourse.julialang.org/u/Jeff_Emanuel)\
**Post date:** [September 29, 2021, 2:36pm UTC](https://discourse.julialang.org/t/basic-struct-usage-questions/68932/21 "2021-09-29T14:36:13Z")

</div>

I think you want parameteric types so that the struct members are not abstract.

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