# Struct/method definition order advice

**URL:** https://discourse.julialang.org/t/struct-method-definition-order-advice/87377
**Category:** General Usage
**Created:** [September 16, 2022, 4:16pm UTC](https://discourse.julialang.org/t/struct-method-definition-order-advice/87377 "2022-09-16T16:16:52Z")
**Posts on this page:** 13
**Page:** 1

<div class="post-metadata">

### Author: ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)
#### Post date: [September 16, 2022, 4:16pm UTC](https://discourse.julialang.org/t/struct-method-definition-order-advice/87377/1 "2022-09-16T16:16:52Z")

</div>

In Julia, you can have

```julia
# in src/monster.jl
struct Monster
end

# in src/player.jl
struct Player
end
capture(::Player, ::Monster)

```

This will only work if `include("src/player.jl")` is done after `include("src/monster.jl")`. Otherwise, Julia complains that `Monster` isn’t defined. I understand the reason for that constraint, but nevertheless, it’s frustrating in large projects. What if I have some other method, `attack(::Monster, ::Player) = ...`, whose logic belongs more in `monster.jl`?

Shuffling code around is frequently a painful exercise because of this.

So I’m looking for advice. Is there some design pattern / perspective that helps? I’ve seen some packages throw the towel, with [src/types.jl](https://github.com/JuliaDebug/JuliaInterpreter.jl/blob/master/src/types.jl), but that is rather depressing.

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [September 16, 2022, 4:27pm UTC](https://discourse.julialang.org/t/struct-method-definition-order-advice/87377/2 "2022-09-16T16:27:01Z")

</div>

You can do forward declarations for functions like so:

```julia
function capture end

```

I usually place these and their docstrings after struct definitions and implement the various methods afterwards, to not run into problems due to order of definition.

---

<div class="post-metadata">

### Author: ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)
#### Post date: [September 16, 2022, 5:28pm UTC](https://discourse.julialang.org/t/struct-method-definition-order-advice/87377/3 "2022-09-16T17:28:33Z")

</div>

My issue is with the struct+method order definition. If you put

```julia
# in src/monster.jl
struct Monster
end
attack(::Monster, ::Player) = 1

# in src/player.jl
struct Player
end

```

and include `monster.jl` first, you get an error that `Player` isn’t defined. Forward declarations don’t help…

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [September 16, 2022, 6:15pm UTC](https://discourse.julialang.org/t/struct-method-definition-order-advice/87377/4 "2022-09-16T18:15:41Z")

</div>

Yes - I’d have a file layout like this:

```julia
# src/structs.jl
struct Monster end

struct Player end

# src/attacks.jl
attack(::Monster, ::Player) = 1.0
attack(::Player, ::Monster) = 2.5

```

or something similar that results in this layout. Since functions and their arguments are not as tightly bound in julia as in e.g. Java or C++ (there is no implicit `self` argument), the way to resolve the definition order is to disentangle your data (the structs) from your operations (your functions). For example, why should `attack` be defined together with `Monster` and not `Player` (and the same goes vice versa)? Both arguments are equally important to decide which method is called, so associating it with either one or the other seems unnatural to me.

---

<div class="post-metadata">

### Author: ![dylanxyz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dylanxyz/32/36646_2.png) [@dylanxyz](https://discourse.julialang.org/u/dylanxyz)
#### Post date: [September 16, 2022, 7:37pm UTC](https://discourse.julialang.org/t/struct-method-definition-order-advice/87377/5 "2022-09-16T19:37:46Z")

</div>

I think one possible solution is to define abstract types. For example:

```julia
# types.jl

abstract type AbstractMonster end
abstract type AbstractPlayer end

# monster.jl

struct Monster <: AbstractMonster
    ...
end

# player.jl

struct Player <: AbstractPlayer
    ...
end

function capture(player::AbstractPlayer, monster::AbstractMonster)
    ...
end

```

Then you just have to `include` `types.jl` first, and as long as you reference the `abstract` types in `player.jl` and `monster.jl` the order of `include`s doesn’t really matter between them.

---

<div class="post-metadata">

### Author: ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)
#### Post date: [September 16, 2022, 7:40pm UTC](https://discourse.julialang.org/t/struct-method-definition-order-advice/87377/6 "2022-09-16T19:40:46Z")

</div>

Yes, I think these `abstract type`s are functionally equivalent to a forward type declaration! It’s a bit awkward, but after fighting to reorganize my code along other lines, I’m very willing to take that.

---

<div class="post-metadata">

### Author: ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)
#### Post date: [September 16, 2022, 7:47pm UTC](https://discourse.julialang.org/t/struct-method-definition-order-advice/87377/7 "2022-09-16T19:47:56Z")

</div>

> [@Sukera](#):
>
> For example, why should `attack` be defined together with `Monster` and not `Player` (and the same goes vice versa)? Both arguments are equally important to decide which method is called, so associating it with either one or the other seems unnatural to me.

It’s about keeping an algorithm readable in one page. Sometimes it makes sense to write `avg_wait_time(::Patient)` close to `struct Patient`, sometimes it’s nicer to have it next to `wait_time(::Hospital)`, but the struct-before-method constraint is limiting.

---

<div class="post-metadata">

### Author: ![mfiano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mfiano/32/37565_2.png) [@mfiano](https://discourse.julialang.org/u/mfiano)
#### Post date: [September 16, 2022, 8:11pm UTC](https://discourse.julialang.org/t/struct-method-definition-order-advice/87377/8 "2022-09-16T20:11:45Z")

</div>

This is a common issue people coming from OOP/single dispatch are upset about. In Julia and other multiple dispatch languages, data is completely disassociated from behavior, so it does not make much sense to put behavior next to data, since the behavior could apply to any combinations of data, and doing so doesn’t make it any more readable.

Instead, it makes much more sense to employ a modular design architecture, without this coupling.

---

<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 16, 2022, 11:01pm UTC](https://discourse.julialang.org/t/struct-method-definition-order-advice/87377/9 "2022-09-16T23:01:11Z")

</div>

There is also the `FromFile.jl` package that allows a more self-contained file structure, somewhat reminiscent of Python modules. I didn’t have much success with it, but the idea seems useful and lots of people use it.

---

<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: [September 16, 2022, 11:17pm UTC](https://discourse.julialang.org/t/struct-method-definition-order-advice/87377/10 "2022-09-16T23:17:23Z")

</div>

Refactoring frequently reused code into a module can let you `import`/`using` repeatedly at the start of each file, so that may be a bit clearer than an `include` order in a distant primary file. But that module still has to exist in advance, often by an early `include` in that primary file, so that doesn’t really solve your problem. But I think this is less a constraint and just the fact that order matters to some degree.

The thread mentioned forward type declarations or delayed definitions (like how a callee function only needs to exist when it is called), and being someone who knows almost nothing about how dispatch is implemented, I find it plausible this could work for dispatch. But types _do_ have to be fully defined before they’re put in fields; forward declarations can’t get around that. For example, you can’t make 2 mutually recursive `isbits` types like `struct A b::B end; struct B a::A end`; no matter what sort of forward declaration is made, it’s not possible for an `A` to directly contain `B` that contains another `A` that contains another `B` etc. This isn’t some quirk of Julia, it’s not possible in [C++ either](https://stackoverflow.com/questions/113385/declare-an-object-even-before-that-class-is-created); a forward-declared type can only be pointed to or referenced before its full definition, and the Julian equivalent would be a `Ref` or abstractly annotated field. But when you need to change how a type is annotated or stored in some contexts just because you can’t be sure it was fully defined yet, that’s still order mattering, just with a bit more flexibility at the cost of complexity. I prefer sensible ordering and simpler code.

---

<div class="post-metadata">

### Author: ![cstjean](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cstjean/32/1444_2.png) [@cstjean](https://discourse.julialang.org/u/cstjean)
#### Post date: [September 17, 2022, 6:57am UTC](https://discourse.julialang.org/t/struct-method-definition-order-advice/87377/11 "2022-09-17T06:57:58Z")

</div>

> [@Benny](#):
>
> But types _do_ have to be fully defined before they’re put in fields; forward declarations can’t get around that.

Yes, that is another constraint, but that one is easy to follow: just “define low-level types first”. The annoyance is that the methods/algos associated to these low-level types will occasionally want to refer to the higher-level types (i.e. `foo(::LowerType, ::HigherType) = ...`), and that doesn’t work without moving the whole algorithm “downstream” _or_ splitting the algo across multiple pages _or_ introducing abstract types.

In C++, as you said, I’d just use the forward type declaration `class HigherType;`.

---

<div class="post-metadata">

### Author: ![bertschi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bertschi/32/33462_2.png) [@bertschi](https://discourse.julialang.org/u/bertschi)
#### Post date: [September 17, 2022, 8:13am UTC](https://discourse.julialang.org/t/struct-method-definition-order-advice/87377/12 "2022-09-17T08:13:57Z")

</div>

The idea that methods belong to types is much less clear in Julia than in OOP languages. I tend to think of generic functions as interfaces that get implemented, i.e., have methods, by different types and usually end up with something like the following structure:

- `interface_*.jl` : Files containing interface defnitions, i.e., forward declarations of generic functions with docstrings describing their intend.  
Reading these files allows to see the abstract functionality at once.

- `type_*.jl`: Files containing type declarations.  
Again, reading these files allows to see supported data types and their layout.

- `implementation_*.jl`: Files containing the actual methods for each interface and type combination.  
Finally, I can dig into the implementation here if needed.

In practice the filenames would be more meaningful though, i.e., in your game example the files might be `game.jl` (for the interfaces), `agents.jl`(for the types) and `game_play.jl` (for the implementations) or something like that.  
In simpler case, i.e., if a method only depends on a single type, it can also implement directly just after the type definition. Similarly, a generic function with a single method can be defined just at its point of use.  
In any case, the `capture(::Player, ::Monster)` and `foo(::LowerType, ::HigherType)` methods belong neither to one nor the other type, i.e., they specify an interaction between types and should be handled accordingly.

---

<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: [September 17, 2022, 10:13am UTC](https://discourse.julialang.org/t/struct-method-definition-order-advice/87377/13 "2022-09-17T10:13:27Z")

</div>

I can appreciate the extra bit of flexibility with forward type declarations; if adapted to Julia and used to extremes, I might be able to forward declare all the types in any order, then define the types and functions in any order as long as the types themselves are defined in a “lower”-“higher” dependency order. But when type declarations need to precede everything and the type definitions have an order, I feel that I’m just adhering to a different kind of order rather than being more free, and that I might as well merge the ordered type definitions with the preceding type declarations. I also prefer if there weren’t many distant forward declarations I need to keep track of, though it wouldn’t be much trouble.

I do recognize that forward declarations would let you define multimethods physically close in the same file to the definition of the first argument’s type, but that informal association (well, if you put each type in its own `module` you could formally mimic class encapsulation) seems more like a singly-dispatched OOP pattern that isn’t needed for multiple dispatch in Julia.
