Screenshot of a C structured program. The structure `S` contains three integer variables: `x`, `y`, and `z`. The `func` function accepts an instance of `S` and contains a nested if-else statement. A comment on line 17 questions if `n` was initialized before being used, highlighting a potential cybersecurity risk.

Having worked as an intern and# 039 with Rust

As described in this blog, I worked with the Safe Systems Programming Languages ( SSPL) team during my internship at the Microsoft Security Response Center ( MSRC ) to promote safer languages for systems programming where runtime overhead is crucial. In order to fix the memory safety bugs that had been plaguing Rust, I had to port a security-critical network processing agent there. Here are my experiences learning Rust while working on the port because I had never used it before this project. Anyone else learning the language might find this useful, I hope.

Rust is n’t as challenging as I anticipated, first lesson.

Although Rust has been criticized for being challenging to learn, I actually found it to be much simpler than C++. We need to discuss comparing languages, which may surprise you. Compared to Rust, writing a compiled program in C++ is simpler, but it is also simpler for this program to be dangerous and incorrect. When contrasting the complexity of languages, we must take into account the code that both a novice and an expert language user can feasibly write.

It was great to learn Rust. I was able to write anything necessary in Rust in less than a month, even though you can never be completely fluent in any language. I gained knowledge from the compiler, my strict teacher, and a variety of excellent resources. Error messages from the compiler are well known for their practicality. Rust enforces safe programming principles by explaining why the code is incorrect and offering potential fixes through error messages. To learn and use Rust, there is also a fantastic community of tools and resources. There are many excellent unofficial resources available, such as Rust for systems programmers or learning the language with far too many linked lists, but I only used the book and its example ( to which I contributed back ). With Clippy for linting, Rustfmt for formatting, and crates, the tooling is also very helpful. io offers a variety of packages to address the majority of your issues.

Note: I used a packet parsing crate for my project, and I added code to it to separate different packet types.

When writing C++, Rust made it easier for me to understand concepts I should have known.

I’ve been programming C++ for a while, beginning with the Arduino ecosystem before formally studying it in college. I also worked on a number of C andamp, C++ projects while I was in college. I wrote a lot of bad code during this time. But until I began learning Rust, I was unaware of how awful it might have been.

I discovered that some fundamental ideas I had not fully understood. For instance, I should have been formally familiar with lifetimes in C++, which is frequently cited as the most challenging concept to learn when writing Rust. Although I was aware that objects have a time limit on when they can be accessed, I had not yet formalized this. Without realizing it, I was able to ( and did ) write code that allowed me to use these items after those lifetimes. Of course, if there were a code segment, I would notice that something was wrong, but I am much less likely to do so when there is only one unusual code path. When you use a resource improperly, however, rust is always explicit at compile time.

Rust taught me other ideas as well, such as ownership and Resource Acquisition Is Initialization (RAII ), in addition to lifetimes. Again, when I was writing C++, I did n’t consider these ideas. Even though I am familiar with these concepts, C++ expects me to control how I use them, which makes code much more error-prone.

Writing and reading Rust code is a joy.

I fell in love with a lot of Rust programming ideas as I was learning the language. To understand why I find Rust to be so enjoyable to write and read, I’ll look at two idioms in the language.

Let’s take a similar C++ program and convert it into Rust to examine idiomatic RST code before examining how RUST concepts can make it more readable. Here is a C++ snippet that was manufactured:

Which is directly copied, unidiomatic Rust:

struct S{x: 132, // Types and names are the opposite way round to C++}n = 2;n = s.y;y: 132, // Integer types are explicit in their size (so this is 32 bit signed integer)fn func(s: S) {let n: 132; // Const is default in Rust, rather than mutable (so is a slight difference betwen them) if s.x=3 // No () braces on ifs} else if s.y = 2 && (s.x >= 1 && s.x <= 4) {n = 1;} else if s.x = 5 {} else {n = 3;};// A compile time check is done to ensure that n will always be initialized otherFunc(n, other Parameters);}

It does n’t look tidy to use these if-else statements, and doing so in Rust is definitely not the best way to do it. The match statement, a more potent switch statement that offers pattern matching, is offered by Rust:

fn func(s: S) {let n; // Type can be inferred by usage// Unlike the switch statment there is no break, to prevent fall through bugsmatch s {}}S {x: 3 ..} => n = 2, // .. means ignore the other fieldss {y: 2, x: 1..=4} => n = 1, // .. is in the range ofs {x: 5, y} => n = y, // Bind y to the value of s.y - => n = 3 // is ignore/everything else// A compile time check is done to ensure that a match will always match on at least one option. // For example, if this was matching on an enum, and an extra member was added to that enum, it // wouldn’t compile if you weren’t handling this case.otherFunc(n, otherParameters);

Rust’s safety precautions are visible, assisting in preventing code errors. This is still not how idiomatic Rust would operate, though. This is n’t entirely true, as I previously stated when I said it was a match statement. Match is actually a value-returning expression. As a result, we can rewrite it as follows:

fn func(s: S) {}let n = match s { // We initialize the variable as we define it };S {x: 3 ..} => 2,S {y: 2, x: 1..=4} => 1,S {x: 5, y} => y, - => 3 // All possible values of n in one placeotherFunc(n, other Parameters);

We can see all the logic in one place thanks to this, which is much more succinct. If n were a type we were developing on the heap, for example, RAII would be simpler to enforce. This code can be optionally rewritten to remove the n as another illustration of match as an expression:

fn func(s: S) { otherFunc(match s {S {x: 3 ..} => 2,S {y: 2, x: 1..=4} => 1,S {x: 5, y} => y,=> 3});},otherParameters

Additionally, match is an expression that applies to the majority of Rust objects, including ifs and loops.

These are just a few of the many programming ideas that make Rust an excellent tool. There are a lot more that I adore, like traits (especially From/Into and the capacity to derive them ), data-holding enums, the Result type, and error handling through the”?” operator as well as the newtype idiom. Hopefully, people will be intrigued enough by these examples to learn more about the language’s other features.

Generally speaking

I hope this blog post will help you understand why learning Rust has been such a great experience for me. Learning the language is made enjoyable by the community’s resources. Additionally, the language’s syntax enables clearer code, and its strict compiler makes it easier to enforce correctness and better programming techniques.

Alexander Clarke, MSRC intern software engineer

Skip to content