IS4010: AI-Enhanced Application Development

Week 10: Welcome to Rust

Brandon M. Greenwell

Session 1: Why rust?

Housekeeping: final project timeline

  • This is a quick reminder that your final project groups must be finalized by the end of this week (Week 10).
  • Your detailed project proposal will be due at the end of next week (Week 11).

Welcome to a new frontier

  • For the next few weeks, we are shifting from python to our second language, rust.
  • Rust is a modern, compiled language focused on three primary goals: performance, reliability, and safety.
  • It has a steeper learning curve than python, but it gives us the power to write incredibly fast and memory-efficient code, which is essential for systems programming, game development, and high-performance computing.

Compiled vs. interpreted languages

  • Python is an interpreted language. An interpreter reads and executes your code line by line. This makes it flexible and easy to use, but it can be slower.
  • Rust is a compiled language. A compiler translates your entire program into machine code—the raw instructions the computer’s cpu understands—before you run it.
  • This ahead-of-time compilation is a major reason for rust’s high performance. It catches errors early and optimizes the code for speed.

Meet cargo, your rust build tool

  • cargo is rust’s official build system and package manager, and it’s one of the language’s best features.
  • It handles creating new projects, compiling your code, running your application, and managing external libraries (called “crates” in rust).
  • We will use these three core commands constantly:
    • cargo new project_name: creates a new “hello, world!” project.
    • cargo build: compiles your code.
    • cargo run: compiles and then runs your application.

Hello, rust!

  • When you run cargo new hello_rust, it creates a simple project structure for you.
  • The main source code lives in src/main.rs.
  • The fn main() block is the entry point for every rust executable.
  • println! is a macro (not a function, note the !) that prints text to the console.
// Inside src/main.rs
fn main() {
    println!("Hello, rust!");
}

Session 2: Rust basics

Variables and mutability

  • We declare variables using the let keyword.
  • A core concept in rust is that variables are immutable by default. Once a value is bound to a name, you can’t change it. This helps us write safer code.
  • To make a variable mutable, you must explicitly use the let mut keyword.
let x = 5; // immutable
let mut y = 10; // mutable
y = 15; // this is allowed
// x = 6; // this would cause a compiler error!

Scalar data types

  • Rust is a statically typed language, meaning the type of every variable must be known at compile time.
  • It has four primary scalar (single value) types:
    • Integers: signed (i32, i64) or unsigned (u8, u32). The number is the bits of space it takes up. i32 is the default.
    • Floating-point numbers: f32 (single-precision) and f64 (double-precision). f64 is the default.
    • Booleans: bool with values true or false.
    • Characters: char, for a single unicode character, denoted with single quotes.

Compound data types

  • Rust has two primary built-in compound types for grouping multiple values.
  • The tuple is a fixed-size collection of values of different types. Once declared, a tuple’s size cannot change.
  • The array is a fixed-size collection where every element must have the same type.
// A tuple with different types
let my_tuple: (i32, f64, u8) = (500, 6.4, 1);

// An array with five elements of the same type
let my_array: [i32; 5] = [1, 2, 3, 4, 5];

Functions in rust

  • We define functions using the fn keyword.
  • You must declare the type of each function parameter.
  • If the function returns a value, you must declare its type after an arrow ->.
  • The final expression in a function is automatically returned; you don’t need the return keyword if it’s at the end.
fn add(num1: i32, num2: i32) -> i32 {
    // No semicolon means this is an expression, and it's returned
    num1 + num2
}

How do we know our code works?

  • In the Python section, we used the pytest library to run our tests.
  • Rust has a powerful testing framework built directly into the language and its tooling.
  • We can write tests for our code and run them from the command line using a simple, built-in command: cargo test.

The anatomy of a rust test

  • Tests are just functions marked with a #[test] attribute.
  • By convention, they are placed in a special module named tests inside the same file as the code they are testing.
  • The #[cfg(test)] attribute tells Rust to only compile and run this code when we execute cargo test.
fn add_two(a: i32) -> i32 {
    a + 2
}

#[cfg(test)]
mod tests {
    use super::*; // Brings `add_two` into scope

    #[test]
    fn it_adds_two() {
        assert_eq!(add_two(2), 4);
    }
}

Assertion macros

  • How do we actually check if our code is correct inside a test? We use assertion macros.
  • A test passes if the function completes without the macro “panicking” (crashing).
  • The most common macros are:
    • assert!(expression): Panics if the expression evaluates to false. Useful for boolean checks.
    • assert_eq!(left, right): Panics if the left and right arguments are not equal. This is the one you will use most often.
    • assert_ne!(left, right): The opposite of assert_eq!. Panics if the arguments are equal.

Our workflow for rust labs

  • For the Rust labs, we will provide the test suite for you.
  • Your workflow should be:
    1. Write your solution code in src/main.rs.
    2. Append our provided test module to the bottom of that file.
    3. Run cargo test in your terminal to check your work locally.
    4. Once all tests pass, commit and push your code to GitHub.
  • This gives you instant feedback without having to wait for the CI/CD pipeline.

Introducing lab 10

  • This week’s lab is the “translate the python” challenge.
  • You will be given several simple python functions and will be tasked with rewriting them in rust.
  • This lab is designed to give you hands-on practice with rust’s syntax, its strict type system, and its function definitions.
  • Full instructions are in labs/lab10/README.md.