···11+---
22+title: Why Rust
33+date: 2020-02-15
44+tags:
55+ - rust
66+ - rant
77+ - satori
88+ - golang
99+---
1010+1111+# Why Rust
1212+1313+Or: A Trip Report from my Satori with Rust and Functional Programming
1414+1515+Software is a very odd field to work in. It is simultaneously an abstract and
1616+physical one. You build systems that can deal with an unfathomable amount of
1717+input and output at the same time. As a job, I peer into the madness of an
1818+unthinking automaton and give order to the inherent chaos. I then emit
1919+incantations to describe what this unthinking automaton should do in my stead. I
2020+cannot possibly track the relations between a hundred thousand transactions
2121+going on in real time, much less file them appropriately so they can be summoned
2222+back should the need arise.
2323+2424+However, this incantation (by necessity) is an _unthinkably_ precise and fickle
2525+beast. It's almost as if you are training a four-year old to go to the store,
2626+but doing it by having them read a grocery list. This grocery list has to be
2727+precise enough that the four year old ends up getting what you want and not a
2828+cart full of frosted flakes and candy bars. But, at the same time, the four year
2929+old needs to understand it. Thus, the precision.
3030+3131+There's many schools of thought around ways to write the grocery list. Some
3232+follow a radically simple approach, relying on the toddler to figure things out
3333+at the store. Sometimes this simpler approach doesn't work out in more obscure
3434+scenarios, like when they are out of red grapes but do have green grapes, but it
3535+tends to work out enough. Proponents of these list-making tools also will
3636+advocate for doing full tests of the grocery list before they send the toddler
3737+off to the store. This means setting up a fake grocery store with funny money, a
3838+fake card, plastic food, the whole nine yards. This can get expensive and can
3939+become a logistical issue (where are you going to store all that plastic fruit
4040+in a way that you can just set up and tear down the grocery store mock so
4141+quickly?).
4242+4343+Another school of thought is that the process of writing the grocery list should
4444+be done in a way that prevents ambiguity at the grocery store. This kind of flow
4545+uses some more advanced concepts like the ability to describe something by its
4646+attributes. For example, this could specify the difference between fruit and
4747+vegetables, and only allow fruit to be put in one place of the cart and only
4848+allow vegetables to be placed in the other. And if the writer of the list tries
4949+to violate this, the list gets rejected and isn't used at all.
5050+5151+There is yet another school of thought that decides that the exact spatial
5252+position of the toddler relative to everything else should be thought of in
5353+advance, along with a process to make sure that nothing is done in an improper
5454+way. This means writing the list can be a lot harder at first, but it's much
5555+less likely to result in the toddler coming back with a weird state. Consider
5656+what happens if two items show up at the same time and the toddler tries to grab
5757+both of them at the same time due to the instructions in the list! They only
5858+have one arm to grab things with, so it just doesn't work. Proponents of the
5959+more strict methods have reference cells and other mechanisms to ensure that the
6060+toddler can only ever grab one thing at a time.
6161+6262+If we were to match these three ludicrous examples to programming languages, the
6363+first would be Lua, the second would be Go and the third would be something like
6464+Haskell or Rust. Software development is a complicated process because the
6565+problems involved with directing that unthinking automaton to do what you want
6666+are hard. There is a lot going on, much in the same way there is a lot going on
6767+when you send a toddler to do your grocery shopping for you.
6868+6969+A good way to look at the tradeoffs involved is to see things as a balance
7070+between two forces, pragmatism and correctness. Languages that are more
7171+pragmatic are easier to develop in, but are mathematically more likely to run
7272+into problems at runtime. Languages that are more correct take more investment
7373+to write up front, but over time the correctness means that there's fewer failed
7474+assumptions about what is going on. The compiler stops you from doing things
7575+that don't make sense to it. This means that it's difficult to literally
7676+impossible to create a bad state at runtime.
7777+7878+Tools like Lua and Go can (and have) been used to develop stable and viable
7979+software. [itch.io][itchio] is written in Lua running on top of nginx and it
8080+handles financial transactions well enough that it's turned into the guy's full
8181+time job. Google uses Go everywhere in their stack, and it's been used to create
8282+powerful tools like Kubernetes, Caddy, and Docker. These tools are trusted
8383+implicitly by a generation of developers, even though the language itself has
8484+its flaws. If you are reading this blog in Firefox, statistically there is Rust
8585+involved in the rendering and viewing of this post. Rust is built for ensuring
8686+that code is _as correct as possible_, even if it means eating into development
8787+time to ensure that.
8888+8989+[itchio]: https://itch.io
9090+9191+In Rust, you don't have to memorize rules about how and when it is safe to
9292+update data in structures, because the compiler ensures you _cannot mess it up
9393+by rejecting the code if you could be messing it up_. You don't have to run your
9494+tests with a race detector or figure out how to expose that in production to
9595+trace down that obscure double-write to a non-threadsafe hashmap, because in
9696+Rust there is no such thing as a non-threadsafe hashmap. There is only a safe
9797+hashmap and only can ever be a safe hashmap.
9898+9999+As an absurd example, consider the following two snippets of code, one in Go and
100100+one in Rust, both of them will put integers into a standard library list and
101101+then print them all out:
102102+103103+```go
104104+l := list.New() // () -> *list.List
105105+for i := 0; i < 5; i++ {
106106+ l.PushBack(i) // interface{} -> ()
107107+}
108108+109109+for e := l.Front(); e != nil; e = e.Next() {
110110+ log.Printf("%T: %v", e.Value, e.Value)
111111+}
112112+```
113113+114114+```rust
115115+let mut vec = Vec::new::<i64>(); // () -> Vec<i64>
116116+117117+for i in 0..5 {
118118+ vec.push(i as i64); // (mut Vec<i64>, i64) -> ()
119119+}
120120+121121+for i in vec.iter() {
122122+ println!("{}", i);
123123+}
124124+```
125125+126126+The Go version uses `interface{}` as the data element because Go [literally
127127+cannot describe types as parameters to functions][gonerics]. The Rust version
128128+took me a bit longer to write, but there is _no_ ambiguity as to what the vector
129129+holds. The Go version can also hold multiple types of data in the same list,
130130+a-la:
131131+132132+[gonerics]: https://golang.org/doc/faq#generics
133133+134134+```go
135135+l := list.New()
136136+l.PushBack(42)
137137+l.PushBack("hotdogs")
138138+l.PushBack(420.69)
139139+```
140140+141141+All of which is valid because in Go, an `interface{}` matches _every kind of
142142+value possible_. An integer is an `interface{}`. A floating-point number is an
143143+`interface{}`. A string is an `interface{}`. A bool is an `interface{}`. Any
144144+custom type you create is an `interface{}`. Normally, this would be very
145145+restrictive and make it difficult to do things like JSON parsing. However the Go
146146+runtime lets you hack around this with [reflection][wtfisreflection].
147147+148148+[wtfisreflection]: https://golangbot.com/reflection/
149149+150150+This allows the standard library to handle things like JSON parsing with
151151+functions [that look like this](https://godoc.org/encoding/json#Unmarshal):
152152+153153+```
154154+func Unmarshal(data []byte, v interface{}) error
155155+```
156156+157157+There's even a set of complicated rules you need to memorize about how to trick
158158+the JSON parser into massaging your data into place. This lets you do things
159159+like this:
160160+161161+```go
162162+type Rilkef struct {
163163+ Foo string `json:"foo"`
164164+ CallToArms string `json:"call_to_arms"`
165165+}
166166+```
167167+168168+This allows the programmer a lot of flexibility while developing and compiling
169169+the code. It's very easy for the compiler to say "oh, hey, that could be
170170+anything, and you gave it some kind of anything, sounds legit to me", but then
171171+the job of ensuring the sanity of the inputs is shunted to _runtime_ rather than
172172+stopped before the code gets deployed. This means you need to test the code in
173173+order to see how it behaves, making sure that _the standard library is doing its
174174+job correctly_. This kind of stuff does not happen in Rust.
175175+176176+The Rust version of this JSON example uses the [serde][serde] and
177177+[serde_json][serdejson] libraries:
178178+179179+[serde]: https://serde.rs
180180+[serdejson]: https://serde.rs/json.html
181181+182182+```rust
183183+use serde::*;
184184+185185+#[derive(Serialize, Deserialize)]
186186+pub struct Rilkef {
187187+ pub foo: String,
188188+ pub call_to_arms: String,
189189+}
190190+```
191191+192192+And the logic for handling the correct rules for serialization and
193193+deserialization is handled at _compile time_ by the compiler itself. Serde also
194194+allows you to support more than just JSON, so this same type can be reused for
195195+Dhall, YAML or whatever you could imagine.
196196+197197+## tl;dr
198198+199199+Rust allows for more correctness at the cost of developer efficiency. This is a
200200+tradeoff, but I think it may actually be worth it. Code that is more correct is
201201+more robust and less prone to failure than code that is less correct. This leads
202202+to software that is less likely to crash at 3 am and wake you up due to a
203203+preventable developer error.
204204+205205+After working in Go for more than half a decade, I'm starting to think that it
206206+is probably a better idea to impact developer velocity and force them to write
207207+software that is more correct. Go works if you are careful about how you handle
208208+it. It however amounts to a giant list of rules that you just have to know (like
209209+maps not being threadsafe) and a lot of those rules come from battle rather than
210210+from the development process.
211211+212212+This came out as more of a rant than I had thought it would, but overall I hope
213213+my point isn't lost.
214214+215215+### Things You Might Complain About
216216+217217+Yes, I know slices exist in Go. I wanted to prove a point about how the overuse
218218+of `interface{}` in some relatively core things (like generic lists) can cause
219219+headaches in term of correctness. Go will reject you trying to append a string
220220+to an integer slice, but you cannot create a type that functions identically to
221221+an integer slice.
222222+223223+Go does have a race detector that will point out a lot of sins in concurrent
224224+programs, but that is again at _runtime_, not at _compile time_.
225225+226226+---
227227+228228+Many thanks to Tene, Sr. Oracle, A. Wilfox, Byte-slice, SiIvagunner and anyone
229229+who watched the stream where I wrote this blogpost. If I got things wrong in
230230+this, please [reach out to me](/contact) to let me know what I messed up. This
231231+is a composite of a few twitter threads and a conversation I had on IRC.
232232+233233+Thanks for reading, be well.