Lecture 12 - Midterm Review

Welcome to Review Day!

You've learned a lot in just a few weeks! Today we'll:

  • Review key concepts you need to master for the midterm
  • Practice with interactive questions
  • Clarify what you need to know vs. what's just context
  • Build confidence for the exam

Reminders about the exam

  • Friday, 12:20-1:10
  • No reference sheets or calculators
  • Two exam versions and set (but not assigned) seating

How Today Works

  1. Quick concept review for each topic
  2. Quick questions think-pair-share and cold calls

Development Tools

Shell/Terminal Commands (Lecture 2)

For the midterm, you should recognize and recall:

  • pwd - where am I?
  • ls - what's here?
  • ls -la - more info and hidden files
  • mkdir folder_name - make a folder
  • cd folder_name - move into a folder
  • cd .. - move up to a parent folder
  • cd ~ - return to the home directory
  • rm filename - delete a file

You DON'T need to: Memorize complex command flags or advanced shell scripting

Git Commands (Lecture 3)

For the midterm, you should recognize and recall:

  • git clone - get a repository, pasting in the HTTPS or SSH link
  • git status - see what's changed
  • git checkout branch_name - switch to a different branch
  • git checkout -b new_branch - create a branch called new_branch and switch to it
  • git add . - stage all recent changes
  • git commit -m "my commit message" - create a commit with staged changes
  • git push - send what's on my machine to GitHub
  • git pull - get changes from GitHub to my machine

You DON'T need to: merge, revert, reset, resolving merge conflicts, pull requests

Cargo Commands (Lecture 5)

For the midterm, you should recognize and recall:

  • cargo new project_name - create project
  • cargo run - compile and run
  • cargo run --release - compile and run with optimizations (slower to compile, faster to run)
  • cargo build - just compile without running
  • cargo check - just check for errors without compiling
  • cargo test - run tests

You DON'T need to: Cargo.toml syntax, how Cargo.lock works, advanced cargo features

Quick Questions: Tools

Question 1

Which command shows your current location on your machine?

Question 2

What's the correct order for the basic Git workflow?

  • A) add → commit → push
  • B) commit → add → push
  • C) push → add → commit
  • D) add → push → commit

Question 3

Which cargo command compiles your code without running it?

Rust Core Concepts

Compilers vs Interpreters (Lecture 4)

Key Concepts

  • Compiled languages (like Rust): Code is transformed into machine code before running
  • Interpreted languages (like Python): Code is executed line-by-line at runtime
  • The compiler checks your code for errors and translates it into machine code
  • The machine code is directly executed by your computer - it isn't Rust anymore!
  • A compiler error means your code failed to translate into machine code
  • A runtime error means your machine code crashed while running

Rust prevents runtime errors by being strict at compile time!

Variables and Types (Lecture 7)

Key Concepts

  • Defining variables: let x = 5;
  • Mutability: Variables are immutable by default, use let mut to allow them to change
  • Shadowing: let x = x + 1; creates a new x value without mut and lets you change types
  • Basic types: i32, f64, bool, char, &str, String
  • Rough variable sizes: Eg. i32 takes up 32-bits of space and its largest positive value is about half of u32's largest value
  • Type annotations: Rust infers types (let x = 5) or you can specify them (let x: i32 = 5)
  • Tuples: Creating (let x = (2,"hi")), accessing (let y = x.0 + 1), destructuring (let (a,b) = x)
  • Constants: Eg. const MY_CONST: i32 = 5, always immutable, must have explicit types, written into machine code at compile-time

What's Not Important

  • Calculating exact variable sizes and max values
  • 2's complement notation for negative integers
  • Complex string manipulation details

String vs &str - You're not responsible for it, but let's talk about it

Quick explanation

  • String = a string = owned text data (like a text file you own)
  • &str = a "string slice = borrowed text data (like looking at someone else's text)
  • A string literal like "hello" is a &str (you don't own it, it's baked into your program)
  • To convert from an &str to a String, use "hello".to_string() or String::from("hello")
  • To convert from a String to an &str, use &my_string (to create a "reference")

Don't stress! You can do most things with either one, and I will not make you do anything crazy with these / penalize you for misusing these on the midterm.

Quick Questions: Rust basics

Question 4

What happens with this code?

#![allow(unused)]
fn main() {
let x = 5;
x = 10;
println!("{}", x);
}
  • A) Prints 5
  • B) Prints 10
  • C) Compiler error
  • D) Runtime error

Question 5

What's the type of x after this code?

#![allow(unused)]
fn main() {
let x = 5;
let x = x as f64;
let x = x > 3.0;
}
  • A) i32
  • B) f64
  • C) bool
  • D) Compiler error

Question 6

How do you access the second element of tuple t = (1, 2, 3)?

  • A) t[1]
  • B) t.1
  • C) t.2
  • D) t(2)

Functions (Lecture 8)

Key Concepts

  • Function signature: fn name(param1: type1, param2: type2) -> return_type, returned value must match return_type
  • Expressions and statements: Expressions reduce to values (no semicolon), statements take actions (end with semicolon)
  • Returning with return or an expression: Ending a function with return x; and x are equivalent
  • {} blocks are scopes and expressions: They reduce to the value of the last expression inside them
  • Unit type: Functions without a return type return ()
  • Best practices: Keep functions small and single-purpose, name them with verbs

What's Not Important

  • Ownership/borrowing mechanics (we'll cover this after the midterm)
  • Advanced function patterns

Quick Questions: Functions

Question 7

What is the value of mystery(x)?

#![allow(unused)]
fn main() {
fn mystery(x: i32) -> i32 {
    x + 5;
}
let x = 1;
mystery(x)
}
  • A) 6
  • B) i32
  • C) ()
  • D) Compiler error

Question 8

Which is a correct function signature for a function that takes two integers and returns their sum?

Question 9

Which version will compile

#![allow(unused)]
fn main() {
// Version A
fn func_a() {
    42
}

// Version B
fn func_b() {
    42;
}
}
  • A) A
  • B) B
  • C) Both
  • D) Neither

Question 10

What does this print?

#![allow(unused)]
fn main() {
let x = println!("hello");
println!("{:?}", x);
}
  • A) hello /n hello
  • B) hello /n ()
  • C) hello
  • D) ()
  • E) Compiler error
  • F) Runtime error

Loops and Arrays (Lecture 9)

Key Concepts

  • Ranges: 1..5 vs 1..=5
  • Arrays: Creating ([5,6] vs [5;6]), accessing (x[i]), 0-indexing
  • If/else: how to write if / else blocks with correct syntax
  • Loop types: for, while, loop - how and when to use each
  • break and continue: For controlling loop flow
  • Basic enumerating for (i, val) in x.iter().enumerate()

What's Not Important

  • Compact notation (let x = if y ... or let y = loop {...)
  • Enumerating over a string array with for (i, &item) in x.iter().enumerate()
  • Labeled loops, breaking out of an outer loop

Quick Questions: Loops & Arrays

Question 11

What's the difference between 1..5 and 1..=5?

Question 12

What does this print?

#![allow(unused)]
fn main() {
for i in 0..3 {
    if i == 1 { continue; }
    println!("{}", i);
}
}

Question 13

How do you get both index and value when looping over an array?

Enums and Pattern Matching (Lecture 10)

Key Concepts

  • Enum definition: Creating custom types with variants
  • Data in variants: Enums can hold data
  • match expressions: syntax by hand, needs to be exhaustive, how to use a catch-all (_)
  • Option<T>: Has Some(value) and None
  • Result<T, E>: HasOk(value) and Err(error)
  • #[derive(Debug)]: For making enums printable
  • #[derive(PartialEq)]: For allowing enums to be compared with == and !=
  • Data extraction: Getting values out of enum variants with match, unwrap, or expect

What's Not Important

  • if let notation
  • writing complex matches (conditional statements, ranges, tuples) - you should understand them but don't have to write them

Quick Questions: Enums & Match

Question 14

What's wrong with this code?

#![allow(unused)]
fn main() {
enum Status {
    Loading,
    Complete,
    Error,
}

match Status::Loading {
    Status::Loading => println!("Loading..."),
    Status::Complete => println!("Done!"),
}
}

Question 15

If a function's return type is Option<i32> what values can it return (can be more than one)?

  • A) Some(i32)
  • B) Ok
  • C) Ok(i32)
  • D) None
  • E) Err

Question 16

What can go in the ???? to get the value out of Some(42)?

#![allow(unused)]
fn main() {
let x = Some(42);
match x {
    Some(????) => println!("Got: {}", ????),
    None => println!("Nothing"),
}
}
  • A) _ and _
  • B) 42 and 42
  • C) x and x
  • D) y and y

Question 17

What does #[derive(Debug)] do?

Error Handling (Lecture 11)

Key Concepts

  • panic! vs Result: Panic when unrecoverable, Result when recoverable
  • Result<T, E> for errors: Ok(value) for success, Err(error) for failure
  • Error propagation: Passing errors up with match or ?
  • unwrap() and expect(): Quick ways to extract values (but they can panic!)
  • The ? operator: Shortcut for "if error, return it; if ok, give me the value" - only works on shared E

Quick Questions: Error Handling

Question 18

When should you use panic! vs Result<T, E>?

Question 19

Why won't this code compile?

#![allow(unused)]
fn main() {
fn parse_number(s: &str) -> Result<i32, String> {
    let num = s.parse::<i32>()?;  // parse() returns Result<i32, ParseIntError>
    Ok(num * 2)
}
}
  • A) The ? operator can't be used in let statements
  • B) You can't multiply by 2 inside Ok()
  • C) The error types don't match: ParseIntError vs String
  • D) Ok doesn't match the Result type

Question 20

When might you extract a value with .unwrap()?

  • A) When you're pretty sure the value will be Ok/Some not Err/None
  • B) When you want the code to crash if the value is Err or None
  • C) When you want the value if Ok/Some but want to ignore it if Err/None
  • D) When you want a more concise version of a match statement

Question 21

What does this return when called with divide(10, 2)?

#![allow(unused)]
fn main() {
fn divide(a: i32, b: i32) -> Result<i32, String> {
    if b == 0 {
        Err("Can't divide by zero".to_string())
    } else {
        Ok(a / b)
    }
}
}

Putting It All Together

What You've Accomplished

In just a few weeks, you've learned:

  • Professional development tools (shell, git, github, cargo)
  • The foundations of a systems programming language
  • Sophisticated pattern matching and error handling techniques

That's genuinely impressive!

And if it doesn't feel fluent yet, give it some time. It's like you memorized your first 500 words in a new spoken language but haven't had much practice actually speaking it yet. It feels awkward, and that's normal.

Midterm Strategy

  • Focus on concepts: Understand the "why" behind the syntax and it will be easier to remember
  • Practice with your hands: Literally and figuratively - practice solving problems, and practice on paper
  • Take big problems step-by-step: Understand each line of code before reading the next. And make a plan before you start to hand-code

Questions and Discussion

What topics would you like to clarify before Wednesday's practice session?

Activity Time - Design your own midterm

No promises, but I do mean it.

You'll find an activity released to you on gradescope to do solo or in groups.

I want you all to spend some time thinking about problems/questions that you could imagine being on our first midterm. If I like your questions, I might include them (or some variation) on the exam!

This also helps me understand what you're finding easy/difficult and where we should focus on Wednesday. It can help you identify areas you might want to brush up on as well.

Aim to come up with 2-3 questions per category (or more!). I'm defining these as:

  • EASY You know the answer now and expect most students in the class will get it right
  • MEDIUM You feel iffy now but bet you will be able to answer it after studying, and it would feel fair to be on exam
  • HARD It would be stressful to turn the page to this question, but you bet you could work your way to partial credit

Requirements for each question:

For each question you create, please include:

  1. The question itself
  2. The answer/solution (if you can solve it)
  3. Why you categorized it as Easy/Medium/Hard

Content Areas to Consider:

Make sure your questions collectively cover the major topics we've studied so far:

  • Tools: git, shell, cargo
  • Rust: Variables, types, functions, loops, enums & match, error handling

Some formats of problems to consider:

  • Definitions
  • Multiple choice
  • Does this compile / what does it return
  • Find and fix the bug
  • Fill-in-the-blank in code
  • Longer hand-coding problems
  • Short answer on concepts (describe how x works...)