Preparing an internal talk for C and Java devs


#1

Hi,

I’ll be giving an internal talk to my coworkers about Rust next week. I’ll have about 45 minutes to introduce the language. Half of them are C devs (mostly working on OpenvSwitch and an internal RTOS), 25% are Java devs, and the rest of the audience does Python and Go. My goal here is to try to sell Rust for internal projects. I think the most receptive portion of the audience will be the C devs, but maybe some Java folks will be interested too.

I have a major problem though: besides Rust, I mostly code in Python, so I don’t know how to show that Rust will solve some of their problems. I do have some knowledge of Java and C, but mostly from school.

I have watched @aturon talk yesterday and I’m planning to watch a couple other before deciding what I’m going to talk about, but here is a list of topics I thought about:

  • ownership and borrowing (cannot not talk about this)
  • ownership and borrowing in the context of multi-threading
  • error handling (that’s one thing I loved coming from python)
  • enums
  • generics
  • the documentation (that’s what got me hooked to Rust in the first place)
  • cargo
  • C bindings

Do you have talks to suggest I could take inspiration from? Blog posts to recommend? Or advice in general?


Where to read about Rust's threading advantages?
#2

45min very short to sell everything.
Memory safety. (From point of view compiler gives errors so less likely to have bugs at runtime which get overlooked.)
Since you don’t mention C++ could include RAII.
How Traits differ from OOP.
Move semantics. (probably not great to sell but good for geeks.)


#3

For the C devs I’d highlight:

Cargo

Need a library? Search crates.io, add a single like to your Cargo.toml, and you’re done. This was one of my biggest things coming from C.

rustfmt

Never argue about whitespace or where your brackets go. You can even set this up on your CI so you don’t even need to think about it.

lazyness

This kinda goes along with the last one, but I’ve found that Rust generally allows me to spend much less energy on boring stuff, when I’m reviewing a PR I’m not focused on looking for use-after-frees or memory leaks because I can trust that the compiler will catch that and I can instead focus on higher-level things like general maintainability.

forced handling of errors

You can’t forget to check if something returned an error/none, this means that when there is a problem you’re going to find out much closer to where the problem actually is.


There’s, of course, lots more you could talk about, but those were the biggest things for me coming from C to Rust.


#4

From a C perspective:

  • malloc() free(). Nope.

  • memcpy() memmove() memcmp() memset() memchr(). Nope. Not without unsafe code.

  • null terminated strings. Nope. That is not how Rust does it. Although you can if you really really want to. (Someone may want to see how) No need for strcpy(), strcat()

As a developer:

  • rustc - point out the wonderfully meaningful messages from rustc. If you get ownership and borrowing wrong it will be the compiler telling you. The compiler is your friend.

  • Rust playground. Find or set up some examples to let your coworkers “have a go” (assuming that internet access is available).

  • The Rust community. Help is at hand.

  • testing - it’s there, and not as an afterthought.

Further reading? these might be suitable…

Small exercises to get you used to reading and writing Rust code:
https://github.com/carols10cents/rustlings

Rust for experienced C/C++ programmers:
https://github.com/nrc/r4cppp


#5

For C:

  • C libraries work well with Rust, and can be wrapped in a (zero-cost) Rust interface to add a layer of safety to them (i.e. automate memory management, enforce handles can’t be used after they’re freed, formally describe their threading limitations, etc.). This is IMHO huge. Rust can make C codebases safer without rewriting the C part.

  • Dependencies are not painful with Cargo. Generics/monomorphisation/inlining means they’re also cheap at run time, so it’s OK to pull dependencies even for small things.


#6

Maybe walk your C people through http://blog.faraday.io/saved-by-the-compiler-parallelizing-a-loop-with-rust-and-rayon/?


Where to read about Rust's threading advantages?
#7

A few other suggestions:

  1. match statements and patterns/destructuring. Match statements are checked for exhaustiveness by the compiler.
  2. No nulls
  3. sane macro system
  4. Procedural macros can help with extra semantic type safety (eg diesel, rocket) and remove some boilerplate. It’s essentially a hook into the compiler.
  5. Builtin tuples
  6. Type system allows for some really cool things (eg session types) but this is likely a talk on its own
  7. Clippy linting
  8. Language is generally hyper focused on correctness
  9. Std iterators
  10. Slices
  11. Stuff like Mutex<T> being the owner of the data. Other languages require a separate (from the data it protects) mutex that surrounds the critical region = error prone.
  12. Closures (that are zero cost)
  13. Move-by-default (mentioned upthread already). I particularly like methods that move self - no more “close() must be idempotent - or is it??” nonsense.

#8

No nulls

Ah I’ll definitely talk about that! NPEs in Java and NoneType doesn't have attribute XYZ in Python are definitely a pain Rust spares me.

Language is generally hyper focused on correctness

Yeah worth insisting on that.

@kornel I’m not sure what you mean by this (I’m quite unfamiliar with ffis):

C libraries work well with Rust, and can be wrapped in a (zero-cost) Rust interface to add a layer of safety to them (i.e. automate memory management, enforce handles can’t be used after they’re freed, formally describe their threading limitations, etc.). This is IMHO huge. Rust can make C codebases safer without rewriting the C part.

How does wrapping a C functions in Rust makes things safer? It’s still C code running, ultimately, isn’t it?

@recombinant

Rust playground. Find or set up some examples to let your coworkers “have a go” (assuming that internet access is available).

Great idea!

Also, all of you mentionned the tooling (clippy, rustfmt, Cargo, unit testing…). I never found that particulartly spectacular, but I guess it’s because I’m coming form python, which has pretty decent tooling already.


#9

It can be made to make usage of the C code safer - the C code has to be correct in the first place, of course.

A quick example (that @kornel mentioned) is memory management. C code will typically have some function to alloc some data on the heap and then another function to free it. But, it’s up to the programmer to ensure they:

  1. Call the free function (or else mem is leaked)
  2. Do not free more than once.
  3. Do not use the data after it’s been freed.

You can wrap this API in Rust which will:

  1. Automatically call the free function (ie implement Drop for the wrapper type that calls it)
  2. Prevent use after free (Drop is called automatically only when the value is dead - cannot use it afterwards.

Threading limitations can be described by, again, wrapping the API in some Rust struct and then implementing (or not) Send/Sync markers - the compiler will then ensure that the code adheres to those restrictions. A contrived example might be some C API that has thread affinity (maybe stashes something in TLS) - you can enforce that the Rust wrapper is !Send and the compiler will prevent moving the wrapper to another thread.

Basically, if you expose the API in Rust, and then users only use the Rust API, you can attach more semantics to the code that the compiler will help to enforce.


#10

Rust can prevent misuse of the code. For example, many libraries have interface in the form of:

handle *h = lib_init();
lib_do_stuff(h);
lib_free(h);

and would do Very Bad Things if you called things out of order:

lib_free(h);
lib_do_stuff(h);

but with Rust, you can put lib_free() in a Drop impl, so it will be called automatically, and never too early.

With some libraries I went further to describe requirements from user’s manual in Rust’s typesystem. For example, LittleCMS can transform images in-place (where source and destination are the same buffer), but only if source and destination types are the same. In C that’s just something you have to be careful about. In Rust I can write something like fn transform_in_place<T, T>(source_type: T, dest_type: T) and Rust allows calling it only if both args have the same type.


#11

Interesting for most of those devs and quite illustrative: Rust solves the iterator invalidation problem quite elegantly through its type system.


#12

This is what I would do:

  • It’s only a primer to spark interest. 45 minutes is much to short to do a full rundown, so when some people know that rust exists and are interested enough to ask you some questions afterward or start reading about it, it’s a success.
  • No one likes to be told that they are doing a shit job, so be a little sensitive when talking about the safety benefits.
    Even if you don’t mean it that way, a c-programmer might hear: “we think you are incompetent, so why don’t you put your sharp tools away and take this kids-proved compiler that doesn’t let you do anything”.
    Frame it as a tool of empowerment. “Python-person, you can do low level stuff too without blowing your foot off! C-Person, you can set up a project and dependencies without developing ulcers.”
  • be honest. Introducing rust into your company will have some drawbacks, and they should be acknowledged.

#13

Great tips so far! I don’t really have anything to add that hasn’t been mentioned yet.

Related reading from end of last year:


#14

I would like to suggest showing some impressive examples of software already built in Rust, and even use that to explain why Rust was created, what practical problems it addresses. It’s not just a language, but mainly a paradigm, which is what makes it important.

There are operating systems, kernel, gui, networking and all built in Rust.

For example, the latest version of firefox has frustrated a lot of people because it dropped support for all the previous plug-ins, but when you look at it from the 10-thousand foot view, there are big plans. In order to execute them, and innovate, more powerful and stable infrastructure needs to be put in place. The current browser codebases are nearing impossibility to maintain and extend adequately as it is, let alone introducing multi-threading, memory safety, gpu acceleration, etc. Those are some of the tenets of Rust specifically.


#15

As a former Java dev I can say there are a few things that drew me to Rust and were ultimately the reason why I fell in love with it

Concurrency

I used to write a lot of Java that was multi-threaded, multi-process and the language has a few concepts (with synchronize blocks, thread pools, etc) that made writing code like that really nice (especially in comparison to, say, C++). Rust can mirror these concepts and even goes above and beyond in them.

Dependency management

Gradle was already a bit of a game changer when it came to easily managing projects and dependencies but cargo is just so much better. Highlight that. Less boilerplate, reproducible builds and really easy configuration in comparison to what people will be used on the Java side.


#16

Thanks for the Java dev perspective!
I’ll be sure to talk about Cargo!


#17

I’m a crappy coder. I need people like those that haunt this place. That said, you need to apply some people skills. Whether you like it or not, you are selling Rust. Don’t attack the other languages. Focus on how Rust solves programming pain. Every language has it’s strengths and weaknesses. There are things that Rust does better than other languages and saves PAIN. I’m more of an architect and my first exposure to Rust was “Memory safe at compile time? Holy crap. That is awesome”. Memory issues suck big time in a large code base. You had me at that. I’m still a newb but there are some things the Rust brings to the table that are not simply cool programming language constructs - they solve major pain points in the actual work of programming.

You don’t want to get into an argument about arcane point for point comparisons of competing languages. This just closes minds and makes everyone defensive.

Just my two cents from a crappy coder.


#18

Enemy number 1 is complexity. Rust help here.
This is C:

// function definition
void foo(int *x, const int *y) { ... }

// use of function, possible spot for logical error(s)
foo(x, x);

How do you debug this? Its a whole class of self-induced errors. In Rust, though:

fn foo(x: &mut [i32], y: &[i32]) { ... }

// the following produces compiler error
foo(&mut x, &x);

The whole class of possible logical errors is eliminated.
This is priceless!


#19

This is the info I usually present to developers who are new to Rust and are going to be working on our project. The beginning info might apply:


#20

Just a question to ask yourself.
Why can’t you talk about ownership on itself. We need no multi threading to make this relevant, specially for C, C++ developers.

Dangling references are everyday concern for C developers (in the form of pointers), Go, Java, and python solve this issue but pay a performance price.

The borrow checker is the ONE feature this developers wont find in their languages, the other features may make Rust usable, but this one feature makes it convenient.

When introducing this language to newcomers, you should introduce them to the concept of zero cost abstractions. This is the one selling point you should stress, as they can achieve the other features with some other language or extension.

As a C++ developer and Rust hobbyist, I have a different mindset now at the time of coding C++. There is a big gain for C and C++ developers on learning Rust, even when it is only about considering your lifetimes.

Good luck with the talk.