Skip to content

Instantly share code, notes, and snippets.

@listochkin
Created January 4, 2015 10:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save listochkin/4c5bd2026868d841e1ff to your computer and use it in GitHub Desktop.
Save listochkin/4c5bd2026868d841e1ff to your computer and use it in GitHub Desktop.
Playing with Rust

Playing with Rust

DRAFT DRAFT DRAFT

I finally got back to my idea of a small Rust project. Here I'll list my findings so far.

You'll notice that I talk about FFI a lot. Maybe that's just me but I see the following ways I can start playing with an emerging language:

  1. Build some webby stuff. A small service for my existing webapp in a different language would be nice. However, HTTP is still not great in Rust (it's getting there!), so I decided not to do it for now.
  2. Just play with it. Write some code with a lot of math or text/csv processing. Project Euler and all that. A good way to learn the language but the utility is somewhat limited.
  3. Integrate with some existing library. I can play with the language and at the same time the final product me be beneficial for the community at large.

At this point I prefer the last option is case of Rust, although that means that my work will involve dealing with FFI. Quite a few people have similar thoughts: if you check projects on Rust-CI many of them (1/3 or 1/4?) are bindings to some preexisting libraries.

It's a pity that FFI doesn't get as much attention as it should. Guides consider this an "advanced" topic. Information on the web is sparse, and my FFI-related questions often stay unanswered on IRC. At the same time reading FFI declarations in Rust can be overwhelming.

On the other hand binding-type projects are extremely valuable for any emerging language community early on, and I feel like we should pay more attention to helping people getting up to speed with FFI.

Anyway, here are my findings so far.

The good:

  1. Cargo is Ok. Not great yet. I kinda like npm's scripts section a lot more than Cargo's build. .toml doesn't bother me at all.
  2. Lifetimes elision is awesome! The best addition to the language since 0.8 days.
  3. Build-in testing is fine. Not BDD-ish but enough for actually getting things done.

The ugly:

  1. Not 100% Rust-related, but in general the world of Native is a huge mess. Compiling, linking, all those command-line flags, .o vs .a vs .so. Why my compiler can produce dynamic libraries but cannot produce static ones? Why I can't produce a library in one go and instead I have to say cc my.c to my.o and cc my.o to libmy.so? Later that libmy.so is referenced as -l my (where's 'lib' part?) but it won't work anyway because I also have to have my DYLD_LIBRARY_PATH set up! Too bad things like that are not covered well enough on the internet.

  2. Rust FFI guide doesn't show how to use C's structs and typedefs from Rust. Besides, there are way too many type aliases involved at the border between C and Rust. libc:: types, c_str, std::ptr and some types that are just too scary! (especially when you see a bunch of them next to error in a terminal):

    error: mismatched types:
    expected `core::option::Option<extern "C" fn(*mut libc::types::common::c95::c_void, u64)
        -> *mut libc::types::common::c95::c_void>`,
    found `core::option::Option<unsafe extern "C" fn(u64)
        -> *mut libc::types::common::c95::c_void>`
    (expected normal fn, found unsafe fn)
    
  3. Rust can't FFI with C macros. For many cases that's fine. People complain on StackOverflow about not being able to reference #defined constants but those are trivial to copy-paste.

    However, if a library decided to export some of its API not as functions but as macros then you're stuck. Either you have to avoid calling these functions or you have to write wrappers in C. Which is kinda strange to be honest: what's the reason why my C code can pick up macro-defined functions from 3rd-party library but my Rust code cannot? The object files are the same, so in theory macro-fuctions should be visible.

    It's even worse in practice. I have to write 2 wrappers: a C wrapper function around a C macro and then write a safe Rust wrapper around an unsafe extern function.

  4. Speaking of libraries, cargo doesn't let one pass -l parameters to rustc without going through the whole build.rs mambo-jambo. In my case the build is simple: 1 .c file, 1 .so/.a file, very similar to a sample from Cargo guide. However, Rust Command API is so verbose compared to a plain Shell script that I wonder why bother describing builds in Rust in a first place.

  5. Docs are still not great. Main guide is great but theme guides are no near as comprehensive as I'd like to. I found myself consulting with the FFI guide (or Lifetimes guide, or Modules guide) and not finding answers there. Then I would go to API reference but it usually way too specific. It can answer 'what parameters this function accepts' and not 'when and how should I use it'. Rust-by-Example should fill this niche but it's still too shallow. Compare that to Node docs that have a narrative around the ways in which this or that API can be used - with examples, discussions about the tradeoffs, etc. I'd love to see something similar for different aspects of Rust APIs.

  6. Also, Rust docs should link to Cargo docs and vice versa. No, a single link somewhere on Index page won't cut it: the guides and API docs should be deeply linked.

  7. Although Rust claims to be almost 1.0 bikeshedding is still at full speed. Almost every library I saw has commits in last month updating to a new Rust nightly.

  8. Finally, updating Rust is cumbersome. Somehow I assumed that Cargo should autoupdate my Rust installation during the build. Turned out that I have to curl | sudo sh --uninstall and curl | sudo sh again to get a new build. Rustup triggers 100+ MiB download even when uninstalling. Still, the build is fast and unless you're on a cellular connection it won't bother you much.

@Fylwind
Copy link

Fylwind commented Dec 4, 2016

Which is kinda strange to be honest: what's the reason why my C code can pick up macro-defined functions from 3rd-party library but my Rust code cannot? The object files are the same, so in theory macro-fuctions should be visible.

Macros aren't functions. Macros are a kind of preprocessor trickery that performs transformations directly on the source code in C. By the time the code has been compiled, no trace of the macros remain in the object files.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment