Skip to content

Instantly share code, notes, and snippets.

@chrisdone
Created October 17, 2018 10:07
Show Gist options
  • Select an option

  • Save chrisdone/b35b19c6faa82017701bb6af0a335d87 to your computer and use it in GitHub Desktop.

Select an option

Save chrisdone/b35b19c6faa82017701bb6af0a335d87 to your computer and use it in GitHub Desktop.
Rust writeup

Rust notes

Here are the notes I took on approaching writing a project in Rust for the first time, from a Haskeller's perspective.

Conclusions

I didn't have any particular trouble worked with and anticipating the needs of the move semantics of Rust. It's not much unlike the experience of dealing with pure/non-pure code in Haskell; you just have to think ahead of time about what your code is really doing. I think the hullabaloo about "satisfying the borrow checker" is exaggerated.

Installation

Installation is pretty much the same as with Stack, via the install page:

curl https://sh.rustup.rs -sSf | sh

And then you add ~/.cargo/bin to PATH.

Setting up the project

Like stack init, this sets up the project:

$ cargo init

There's a Cargo.toml file similar to a .cabal file, in there you can put your dependencies:

[dependencies]
time = "0.1.12"
regex = "0.1.41"

This feels a bit like specifying extra-deps in your stack.yaml file, and running other cargo commands will update an additional Cargo.lock file automatically, which is like maintaining your own personal stackage snapshot (or a cabal freeze) for the project.

I'm not sure whether that's the best idea: stackage snapshots are shared which I think is better - if I want to be sure two projects build together I can just make sure two teams use the same lts version.

Running, compiling & auto-downloading deps

They have cargo run which automatically installs and compiles everything, familiar to stack users:

chris@precision:~/Work/chrisdone/pid1-rust$ cargo run
    Updating registry `https://github.com/rust-lang/crates.io-index`
 Downloading regex v0.1.80
 Downloading time v0.1.40
 Downloading memchr v0.1.11
 Downloading thread_local v0.2.7
 Downloading regex-syntax v0.3.9
 Downloading aho-corasick v0.5.3
 Downloading utf8-ranges v0.1.3
 Downloading libc v0.2.43
 Downloading thread-id v2.0.0
 Downloading kernel32-sys v0.2.2
 Downloading winapi v0.2.8
 Downloading winapi-build v0.1.1
   Compiling winapi-build v0.1.1
   Compiling winapi v0.2.8
   Compiling libc v0.2.43
   Compiling utf8-ranges v0.1.3

Emacs integration

I found a rust-mode for Emacs: https://github.com/rust-lang/rust-mode

It's pretty much just syntax highlighting, but it works fine.

I installed https://github.com/rust-lang/rust-mode#formatting-with-rustfmt

But it errors out when running with a weird error:

chris@precision:~/Work/chrisdone/pid1-rust$ /home/chris/.cargo/bin/rustfmt
    error: toolchain 'stable-x86_64-unknown-linux-gnu' does not have the binary `rustfmt`

I had to force installation with

cargo install rustfmt --force

But that still doesn't work from Emacs:

cond: Rustfmt failed, see *rustfmt* buffer for details

So I don't currently have Emacs-integrated auto-formatting. I gave up on it.

Dev cycle

$ cargo install cargo-watch

Like stack --file-watch there is cargo-watch with which you can run e.g.

$ cargo watch --exec 'run'

To compile and run an executable. Differences seems to be that:

  • cargo watch looks at the whole directory, not your package's actual source files. So it'll rebuild a lot more often. Emacs, for example, creates hidden backup files in the source dir and cargo watch reacts to this.
  • It seems that cargo watch will actually interrupts the program when a change has occurred, which should be nice for developing web servers (auto-restart).

A REPL in Rust?

There is a project called rusti,

https://github.com/murarth/rusti

But it requires the nightly rust version. I attempted to build it but failed. However, once that stabilises, it should be a handy addition to a rustacean's tool-belt like GHCi.

Runtime & static executables

I learned that Rust does have a standard library which is linked to, and it also uses libc. But you can forgo these if you want a completely bare executable. [from the FAQ]

Does Rust have a runtime? Not in the typical sense used by languages such as Java, but parts of the Rust standard library can be considered a “runtime”, providing a heap, backtraces, unwinding, and stack guards. There is a small amount of initialization code that runs before the user’s main function. The Rust standard library additionally links to the C standard library, which does similar runtime initialization. Rust code can be compiled without the standard library, in which case the runtime is roughly equivalent to C’s.

Additionally, I found this useful project for making completely static Rust executables using docker and musl:

https://github.com/emk/rust-musl-builder

I ran this script:

$ rust-musl-builder cargo build --release

And now my executable is static:

$ ldd target/x86_64-unknown-linux-musl/release/pid1-rust
    not a dynamic executable

Strings

Strings in Rust are apparently all ByteStrings that are interpreted as UTF-8, which means you cannot have e.g. O(1) unicode point access. That's alright, because text processing is Hard anyway; we'd probably be better off if the text package worked like that anyway (encode/decode less often).

In any case it's an improvement over Haskell.

From the FAQ:

How do I do O(1) character access in a String? You cannot. At least not without a firm understanding of what you mean by “character”, and preprocessing the string to find the index of the desired character.

Rust strings are UTF-8 encoded. A single visual character in UTF-8
is not necessarily a single byte as it would be in an
ASCII-encoded string. Each byte is called a “code unit” (in
UTF-16, code units are 2 bytes; in UTF-32 they are 4 bytes). “Code
points” are composed of one or more code units, and combine in
“grapheme clusters” which most closely approximate characters.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment