Skip to content

Commit 603e090

Browse files
authored
Merge pull request #22 from killercup/post/rust-code-order
Rust Code Order
2 parents 9fc4225 + dd034b6 commit 603e090

1 file changed

Lines changed: 100 additions & 0 deletions

File tree

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
---
2+
title: How to order Rust code
3+
categories:
4+
- rust
5+
---
6+
**Note:**
7+
This post is about how I arrange the code I write in Rust.
8+
If you wanted to "order" Rust code
9+
in the "hire someone to write code" sense,
10+
you should still keep on reading
11+
as this is excellent material for a job interview.
12+
(Not the opinion I present but having an opinion on the topic.)
13+
14+
## Arrange code to be in the suggested reading order
15+
16+
I try to order the functions/modules/items in my source files
17+
going from most high-level to most-concrete/small-scope.
18+
You might call it **`fn main` first**.
19+
20+
I do this so that when someone opens the file and starts reading
21+
they can get the general idea of what this file is about very quickly
22+
and then, if needed, dive into the details they are looking for.
23+
I think this works especially well for the entry files in a project.
24+
25+
The opposite position would be to start with
26+
the generic helpers, then introduce domain specific types and functions,
27+
and finally have a `main` function
28+
that calls all the things you've defined above it.
29+
I tend to read these files by scrolling to the end
30+
and then moving upwards;
31+
so it just feels weird to someone used to reading European languages.
32+
33+
## This is not necessarily the order I write code in
34+
35+
I typically don't sit down,
36+
write code from top to bottom,
37+
and end up with a perfectly structured and arranged file.
38+
That is not the goal at all:
39+
It's easy enough to copy and paste parts of a file into another,
40+
or use editor/language plugin features to quickly navigate between sections of files
41+
when I'm looking for something specific.
42+
Remember:
43+
My goal of arranging code in the way described above is
44+
for when you read it for the first time.
45+
46+
## Some specifics about Rust code
47+
48+
The order of items usually doesn't matter in Rust
49+
(macros are a weird edge-case).
50+
There are some things to decide though:
51+
52+
### How to order type definitions (struct, enums) and their implementations?
53+
54+
There are two obvious choices:
55+
56+
- Define all the types first and then list all the implementations?
57+
- Interleave the implementations with the types?
58+
59+
I personally am fine with both,
60+
and tend to go with the latter.
61+
I might however split `impl` blocks up
62+
and define some methods (especially private ones)
63+
right next to the functions they are needed for.
64+
(This sometimes feels like ad-hoc single-instance traits.)
65+
66+
[@matklad] had another interesting comment:
67+
68+
> [I] love to read types upfront
69+
> (if you know the set of fields, you know all potential methods that can exists)
70+
71+
### Split public and private interfaces
72+
73+
When the entry file of a package or module[^1] gets to long,
74+
you want to split it up.
75+
A solid approach is to move implementation details are in a separate file,
76+
which might end up being an "helpers" file
77+
or actually be most of the code split up in modules
78+
that are not exposed to the outside.
79+
80+
[^1]: "Package or module"? Yes, and also "application" and "function": This is a fractal property.
81+
82+
In languages that allow specifying the visibility of items on a very granular level
83+
you can very precisely mark only parts of your code as "public interface".
84+
But this means also means that there is a non-public interface:
85+
Indeed, most abstractions have two interfaces:
86+
A public, consumer-facing one,
87+
and an internal one, for "producers".
88+
Consciously separating the two by the layout of your code
89+
will help create maintainable and comprehensible code bases.
90+
91+
### Abstractions on top of abstractions
92+
93+
Often, you end up writing structures that are only used internally
94+
but then get converted into other structures for the consumers of your package/module.
95+
I don't have a good recipe on how to deal with that,
96+
except that I would recommend trying to
97+
the boilerplate/conversion part "obvious"/invisible and
98+
thus highlight the differentiating details.
99+
100+
[@matklad]: https://github.com/matklad

0 commit comments

Comments
 (0)