Why I Like Rust: Documentation
The other day, I was helping a friend learn Python. They were writing a simple HTTP request to an API, and at one point they asked me "what does requests.get(...).json()
return? A string or a parsed JSON object?”
I thought this would be a good "teach a man to fish" sort of lesson: look it up the docs. requests is a massively popular library that forms the bedrock of many Python scripts. Here's what the documentation has to say:
json(**kwargs)
Returns the json-encoded content of a response, if any.
Parameters:**kwargs – Optional arguments that json.loads takes.
Brutal. It barely answers the question. The description says it "returns a json-encoded value". It wouldn't make sense to call a python object "encoded", so is it a JSON encoded string.
Well, no. Looking at the parameter, json.loads()
is called internally. That would only make sense if json()
returned a deserialized value. This is, in fact, the correct answer, conveyed through pure luck in an optional parameter.
And what happens if the body is not JSON? Does it return None? Does it throw? What kind of exception should I catch?
In truth, the Pythonic answer to this question is "try it for yourself". Boot up a python interactive console, pip install requests, dig up a fake API to hit, and see what it returns. Hope and pray that you don't hit some snag along the way.
Let's see how Rust handles this.
https://docs.rs/reqwest/latest/reqwest/blocking/struct.Response.html#method.json
We've got:
A clear answer: it returns the deserialized object. Specifically from the content body.
A short example. In case you need a little context.
Gotchas: you'll need to enable the JSON feature.Rust libraries generally only make you pay for what you use. If you don't need JSON support, it won't even download the dependency.
Failure cases: If it's not JSON, the Result will return a specific error.
Further, the broader docs experience is phenomenal:
A single global website (docs.rs) where all Rust docs are hosted.
Real, symbol-based doc search.
Source files. I can browse the exact version of the code that I'm exploring.
Inter-library links for symbols! Even across crates, with versioning.
This isn't an exception, it's the rule. Here are a random sampling of libraries I recently pulled for a project: [hyper, petgraph, base64]. And just look at the standard library! Beautiful. Rust has somehow managed to cultivate an ecosystem where this quality of documentation is the standard.
I can't begin to tell you how pleasant this makes developing in Rust. When people ask me why I enjoy the language, sometimes it's hard to convey. It's the little things. Discovering new libraries is fun. It's a new box of toys you can pick through, not a slog of trying to dig up arcane, undocumented knowledge.
People assume the "Rewrite it in Rust" is popular because of memory safety, but I have this sneaking feeling that an even larger part is because developing in Rust is just so dang lovely. Of course I want all my libraries to be this level of quality. Who wouldn't?
Nothing Rust is doing here is particularly novel, nor technically complex. Heavily inspired by GoSee gofmt and godoc., Rust has a focus on strong, unified tooling. Any Rust library can trivially generate docs with a few config settings. Slap #![warn(missing_docs)]
and clippy will automatically warn on public symbols missing docs.
But there's also something bigger at work here. Rust sets the bar high. When I'm surrounded by incredible documentation, it feels shoddy to release a library with anything less. It's not a 'gun to the head' kind of threat. It's more like walking into a nice home and feeling like you want to take off your shoes. Everyone here takes so much pride in their work, that it feels good to maintain that. Quality breeds more quality.