# What are the uses of some of the numerous "types" in Julia e.g., structs, modules?

**URL:** <https://discourse.julialang.org/t/what-are-the-uses-of-some-of-the-numerous-types-in-julia-e-g-structs-modules/100708>\
**Category:** New to Julia\
**Tags:** question, type\
**Created:** [June 22, 2023, 7:02pm UTC](https://discourse.julialang.org/t/what-are-the-uses-of-some-of-the-numerous-types-in-julia-e-g-structs-modules/100708 "2023-06-22T19:02:47Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![markjholmes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/markjholmes/32/34139_2.png) [@markjholmes](https://discourse.julialang.org/u/markjholmes)\
**Post date:** [June 22, 2023, 7:02pm UTC](https://discourse.julialang.org/t/what-are-the-uses-of-some-of-the-numerous-types-in-julia-e-g-structs-modules/100708/1 "2023-06-22T19:02:47Z")

</div>

As a non-computer-scientist, I don’t understand when I’d use e.g., `struct` or `module` (which seem to be fundamental in [the essentials](https://docs.julialang.org/en/v1/base/base/)) beyond “properness” or if designing a package? I find that [the examples presented](https://docs.julialang.org/en/v1/base/base/#struct) are so simple as to not be particularly informative as to _why_ you would use them.

I seem to get by using just `function`s, `array`s, and `tuple`s but looking at the base documentation makes me wonder whether I’m working suboptimally or untidily?

From conversations with others I gather that there comes a point when you may be supplying very numerous or complicated arguments and defining a `struct` is a better/safer way to manage things, but I don’t have a clear idea of what such a situation would look like or where the “tipping point” would be where this would become more optimal.

---

<div class="post-metadata">

**Author:** ![goerz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerz/32/3269_2.png) [@goerz](https://discourse.julialang.org/u/goerz)\
**Post date:** [June 22, 2023, 7:58pm UTC](https://discourse.julialang.org/t/what-are-the-uses-of-some-of-the-numerous-types-in-julia-e-g-structs-modules/100708/2 "2023-06-22T19:58:33Z")

</div>

This isn’t specific to Julia but applies to all languages that have object-orientation or user-defined data structures. There are two typical uses for structs/objects: (1) abstraction, and (2) encapsulation.

Abstraction is for when you have a domain-specific “object” that you want to reason about or operate on. Since you probably have a math background, consider that mathematics behaves similarly. You might say that numbers are the “built-in” data types of mathematics. Not using structs in Julia is the equivalent of doing “just algebra” in math. But then you start defining abstractions once you move to a more specific domain, e.g., geometry. You then ask questions like “At what point do two lines cross?” after you’ve _defined_ “line” and “point” as something you want to reason about. As such, the `Point` struct in the documentation is not just a trivial example. If you’re writing geometry-related code, you actually _want_ to define such structs to simplify your code.

Another aspect of abstractions is that they are often the key to generalization: consider that you could define the abstract behavior of points (via methods) which would then still apply if you wanted to formulate a `Point3D` or `PointSphericalCoordinates` struct later on.

The second reason to use structs is for the encapsulation and management of state. Consider [what happens internally](https://docs.sciml.ai/DiffEqDocs/stable/basics/integrator/#integrator) when you use `DifferentialEquations` to solve the ODE that you set up with `ModelingToolkit`:

```julia
integrator = init(prob, alg; kwargs...)

```

The `prob` here again is an example of “abstraction”, but the `integrator` is an object that holds the state of the solver between steps (the state vector, the current time, etc.)

Another example for “state management” is the situation where you find your function has 20 input parameters (which are then maybe passed to another function). To simplify the code, you can wrap all of these parameters into a struct to be able to pass it around more easily.

State management is a much trickier use of structs than abstraction, simply because management of state is basically _the_ problem of programming (even more so once you get to questions of concurrency). Managing state is hard, and virtually all non-trivial bugs stem from the mismanagement of state, which is probably why the example in the documentation deals with the easier “abstraction” use case.

An important part of encapsulation is that it can hide complexity by having private fields. For example, the `integrator` [only documents “useful” fields](https://docs.sciml.ai/DiffEqDocs/stable/basics/integrator/#Handling-Integrators). This is especially true in Julia, where it is quite common for the fields of structs to be considered completely private, maybe accessible as [properties](https://discourse.julialang.org/t/whats-the-difference-between-fields-and-properties/12495/5) or more commonly via [accessor methods](https://discourse.julialang.org/t/is-accessing-the-fields-of-a-struct-a-good-julia-style/23623/3). In many cases, [interfaces](https://docs.julialang.org/en/v1/manual/interfaces/) are defined purely in terms of methods.

Generally, “abstraction” structs should be immutable, while “state management” structs are mutable (or at least have mutable components), so Julia actually makes the distinction somewhat more clear than other languages by having the `mutable` keyword.

---

<div class="post-metadata">

**Author:** ![frylock](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/frylock/32/50213_2.png) [@frylock](https://discourse.julialang.org/u/frylock)\
**Post date:** [June 22, 2023, 8:02pm UTC](https://discourse.julialang.org/t/what-are-the-uses-of-some-of-the-numerous-types-in-julia-e-g-structs-modules/100708/3 "2023-06-22T20:02:18Z")

</div>

I’m not sure how you use or want to use Julia, but if you get by with tuples, functions and arrays … there isn’t anything necessarily wrong with what you are doing - but it may be possible to express your ideas more abstractly (and more maintainable) with structures.

Before I made efforts to make my code [idiomatic](https://www.quora.com/What-do-you-mean-by-idiomatic-code-in-computer-programming) in the past, I found that if I came back to it later - I couldn’t read it anymore.

EDIT: link is to ChatGPT-generated definition of _idomatic_ on Quora.

---

<div class="post-metadata">

**Author:** ![heliosdrm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heliosdrm/32/3851_2.png) [@heliosdrm](https://discourse.julialang.org/u/heliosdrm)\
**Post date:** [June 22, 2023, 8:08pm UTC](https://discourse.julialang.org/t/what-are-the-uses-of-some-of-the-numerous-types-in-julia-e-g-structs-modules/100708/4 "2023-06-22T20:08:59Z")

</div>

> [@markjholmes](#):
>
> I seem to get by using just `function`s, `array`s, and `tuple`s but looking at the base documentation makes me wonder whether I’m working suboptimally or untidily?

It’s perfectly ok if you use only functions, arrays and tuples. Maybe the structure of the data and routines that you use is sufficiently simple and that’s all you need.

> [@markjholmes](#):
>
> From conversations with others I gather that there comes a point when you may be supplying very numerous or complicated arguments and defining a `struct` is a better/safer way to manage things

That’s right. And an additional advantage of `struct`s is that they can be used to define particular [methods](https://docs.julialang.org/en/v1/manual/methods/) of any function for those types. (See a [gentle explanation](https://towardsdatascience.com/how-julia-perfected-multiple-dispatch-16675db772c2) by Emma Boudreau about this.)

---

<div class="post-metadata">

**Author:** ![heliosdrm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heliosdrm/32/3851_2.png) [@heliosdrm](https://discourse.julialang.org/u/heliosdrm)\
**Post date:** [June 22, 2023, 8:41pm UTC](https://discourse.julialang.org/t/what-are-the-uses-of-some-of-the-numerous-types-in-julia-e-g-structs-modules/100708/5 "2023-06-22T20:41:31Z")

</div>

I forgot that you also mentioned the modules. They have different uses, the most remarkable being that they are the basis of packages. But they can also be used for something as simple as to create separate namespaces for functions, variables, etc.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [June 22, 2023, 11:38pm UTC](https://discourse.julialang.org/t/what-are-the-uses-of-some-of-the-numerous-types-in-julia-e-g-structs-modules/100708/6 "2023-06-22T23:38:21Z")

</div>

Hopefully I can provide a simple cliff notes version with no links or much theory.

Modules are not types. A module creates an independent global scope that encapsulates names, aka namespace. Use imports to allow modules to share select names with each other.

Structs are not a Julia thing, they’re in every language I know of. People already mentioned Julia-specific details, so I’ll stick to the universal basics. A struct is actually very close to a tuple; they both package multiple fields of data (or pointers to data) into a fixed size of memory. The differences are (1) the struct has a name, and (2) the fields have names. Besides names being important for description and subtyping, it can be necessary to distinguish two types with identical internal structure that share functions. For a simple example, let’s say I want to implement a plotting library, nothing fancy, just 2D Cartesian and polar plots with Float64 values. But both kinds of coordinates have 2 points, so if I go with tuples I must use the function name to distinguish them:

```julia
function polarplot(coordinates::Vector{Tuple{Float64, Float64}}) ... end
function Cartesianplot(coordinates::Vector{Tuple{Float64, Float64}}) ... end

```

But wouldn’t it be nice if that information was put in the Vector itself and I could just `plot` either without explicit checks of whether it’s polar or Cartesian? It’d be necessary if I receive a `Vector` with no external indication of which. Well with structs we can handle this:

```julia
struct Cartesian
  x::Float64
  y::Float64
end

struct Polar
  r::Float64
  p::Float64
end

function plot(coordinates::Vector{Cartesian}) ... end
function plot(coordinates::Vector{Polar}) ... end

```

If you don’t ever need to distinguish structurally identical types like this, you could probably pull off everything with tuples, but even then, you may appreciate the clarity that names give here. You can also name fields without naming the overall type with NamedTuples, the (2) without the (1).

---

<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:** [June 23, 2023, 4:46am UTC](https://discourse.julialang.org/t/what-are-the-uses-of-some-of-the-numerous-types-in-julia-e-g-structs-modules/100708/7 "2023-06-23T04:46:44Z")

</div>

Maybe you gathered this from the other comments but: don’t worry about modules. If you don’t know what they do you don’t need them.

Structs on the other hand are really useful, it’s probably worth familiarizing yourself. It’s like `class` in oop languages, it defines a `Type`.

---

<div class="post-metadata">

**Author:** ![Eben60](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/eben60/32/13475_2.png) [@Eben60](https://discourse.julialang.org/u/Eben60)\
**Post date:** [June 23, 2023, 9:27am UTC](https://discourse.julialang.org/t/what-are-the-uses-of-some-of-the-numerous-types-in-julia-e-g-structs-modules/100708/8 "2023-06-23T09:27:13Z")

</div>

> [@markjholmes](#):
>
> I seem to get by using just `function`s, `array`s, and `tuple`s

If you don’t develope packages of your own, that’s sufficient for most purposes. I’d only add `NamedTuple` into the mix.

> [@markjholmes](#):
>
> supplying very numerous or complicated arguments and defining a `struct` is a better/safer way to manage things

That can be one of the uses for `NamedTuple`

---

<div class="post-metadata">

**Author:** ![markjholmes](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/markjholmes/32/34139_2.png) [@markjholmes](https://discourse.julialang.org/u/markjholmes)\
**Post date:** [June 23, 2023, 12:53pm UTC](https://discourse.julialang.org/t/what-are-the-uses-of-some-of-the-numerous-types-in-julia-e-g-structs-modules/100708/9 "2023-06-23T12:53:41Z")

</div>

Blown away by all the help and advice given here, thanks everyone! I’ll try and digest this all

---

<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:** [June 23, 2023, 1:02pm UTC](https://discourse.julialang.org/t/what-are-the-uses-of-some-of-the-numerous-types-in-julia-e-g-structs-modules/100708/10 "2023-06-23T13:02:34Z")

</div>

Another fundamental utility of structs in Julia is to extend methods, for example:

```julia
module MyModule
     export MyData, plot
     import Plots: plot
     struct MyData
        x::Vector{Float64}
        y::Vector{Float64}
     end
     plot(data::MyData) = plot(data.x, data.y, title="MyData Plot")
end

```

And then, you can do:

```julia
julia> module MyModule
            export MyData, plot
            import Plots: plot
            struct MyData
               x::Vector{Float64}
               y::Vector{Float64}
            end
            plot(data::MyData) = plot(data.x, data.y, title="MyData Plot")
       end
Main.MyModule

julia> using .MyModule

julia> data = MyData(rand(10),rand(10));

julia> plot(data)

```

and get the customized plot for your data.

(I added a module here to help understanding what modules can be useful for, organization-wise)

---

<div class="post-metadata">

**Author:** ![heliosdrm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heliosdrm/32/3851_2.png) [@heliosdrm](https://discourse.julialang.org/u/heliosdrm)\
**Post date:** [June 23, 2023, 5:20pm UTC](https://discourse.julialang.org/t/what-are-the-uses-of-some-of-the-numerous-types-in-julia-e-g-structs-modules/100708/11 "2023-06-23T17:20:59Z")

</div>

> [@gustaphe](#):
>
> Maybe you gathered this from the other comments but: don’t worry about modules. If you don’t know what they do you don’t need them.

I agree with this.

> [@gustaphe](#):
>
> Structs on the other hand are really useful, it’s probably worth familiarizing yourself. It’s like `class` in oop languages, it defines a `Type`.

And partly with this too, but I wouldn’t put those two suggestions together. For people who don’t need the advantages of modules, and feel more comfortable leaving aside the complexities of working with them, the situation will probably be the same with respect to structs/types, and they can use named tuples instead, as @Eben60 suggests.

It should be taken into account that modules and types can bring some headaches when you are working on the code, renaming or rewriting parts of it. And if that changing code includes type definitions, the best way of working around those complications is to use modules to encapsulate them!

---

<div class="post-metadata">

**Author:** ![mrufsvold](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mrufsvold/32/31600_2.png) [@mrufsvold](https://discourse.julialang.org/u/mrufsvold)\
**Post date:** [June 23, 2023, 6:54pm UTC](https://discourse.julialang.org/t/what-are-the-uses-of-some-of-the-numerous-types-in-julia-e-g-structs-modules/100708/12 "2023-06-23T18:54:18Z")

</div>

I, too, am no computer scientist. Just a lowly data scientist with a degree in philosophy. That said, I’ve found structs and types very useful. Just a small example that I hit recently:

I work with health care data where National Provider Identifiers (NPI) come up a lot. NPIs are 10 digits and always start with a ‘1’. But depending on the data source I’m reading, it might come to me as an integer, float, or string. There might be missing values. Ah, the wonders of data cleaning.

Also, strings and integers are bad representations of NPI because they allow all sorts of silly operations that don’t make sense for an ID. What does `npi * 10` mean?

But, here is where types come in:

```julia
struct Npi
    x::Int64
    function Npi(x::Int64)
        @assert 999_999_999 < x < 2_000_000_000
        return new(x)
    end
end
Npi(x::Float64) = Npi(convert(Int64, x))
function Npi(x::AbstractString)
    digits_only = replace(x, r"[^\d]*"=> "")
    int_npi = parse(Int64, digits_only)
    return Npi(int_npi)
end

```

Now, I can take the NPI column of any dataframe and do `df[!, :npi] = Npi.(df[:, :npi])` to convert it. I know that any time I interact with a column of type `Npi`, I have some guarantees about its data quality.

Furthermore, I can no longer do silly things like add two NPIs together. I only have the functions available that I explicitly define. This means that at the level of the type system, I am protected from careless errors that can turn into really hairy bugs.

---

<div class="post-metadata">

**Author:** ![simsurace](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simsurace/32/30216_2.png) [@simsurace](https://discourse.julialang.org/u/simsurace)\
**Post date:** [June 24, 2023, 7:58am UTC](https://discourse.julialang.org/t/what-are-the-uses-of-some-of-the-numerous-types-in-julia-e-g-structs-modules/100708/13 "2023-06-24T07:58:22Z")

</div>

That‘s a great and simple example of how the right abstractions make your code less error-prone.

---

<div class="post-metadata">

**Author:** ![tim.holy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tim.holy/32/52_2.png) [@tim.holy](https://discourse.julialang.org/u/tim.holy)\
**Post date:** [June 24, 2023, 11:30am UTC](https://discourse.julialang.org/t/what-are-the-uses-of-some-of-the-numerous-types-in-julia-e-g-structs-modules/100708/14 "2023-06-24T11:30:12Z")

</div>

To try to add to the simple examples: recently I converted someone’s code in another language to Julia. The hardest part was that while that language does support its own version of structs, a lot of the code you see in the wild seems to try encode “meaning by position” within an array. For example, when reading or modifying the code you just have to know that `experiment[1]` is the date on which an experiment was performed, `experiment[2]` was the animal ID, etc. The code becomes much easier to read if you can instead can use `experiment.date` and `experiment.animal` to extract specific bits of information. It’s also easier to keep working if you at some point decide you want to change the data stored in an `experiment`: you don’t have the horrific task of changing all relevant `2`s in your code to a `3` and so on.
